This article describes a Java program that utilizes class library loader ClassLoad to update some of the functional modules in runtime, and makes a simple comparison with dynamic link library schemes that achieve the same functionality in C / C .
Introducing in the design of the embedded system, often involves the design of some functional modules at runtime. For example, a device for data acquisition and processing, including data acquisition, data transmission, command reception, etc., it is possible to send data to a new data processing system while continuing data acquisition while continuing data acquisition. In this case, the function module sent by updated data must be dynamically dynamically active at runtime.
In C / C , such functions can be easily implemented using dynamic link libraries. Win32 API Functions LoadLibrary and Freelibrary provide a function of loading a new functional module and release memory space at runtime. The function module that needs to be updated is packaged in a dynamic connection library, and the main program uses the LoadLibrary function to load the dynamic link library, then calls the function module. When you need to update a functional module, you will first terminate the function module, uninstall the existing dynamic link library using the Freelibrary function, send the new dynamic link library file to the specified directory through the network or other communication port, then use again The LoadLibrary function loads a new dynamic link library and calls the new functional modules. (Refer to the relevant part of Reference 1 if you need to further understand the contents of the dynamic link library programming.)
In Java, there is an abstract class ClassLoad that is called the class library loader to achieve a function similar to the LoadLibrary. The following part of this article focuses on the general structure of ClassLoader and updating the partial function module using the ClassLoader implementation of the partial function module.
Class library loader class library loader ClassLoader is an abstract class responsible for loading class libraries. It accepts the name of a class library and attempts to locate and generate data containing the definition of the class library. The usual implementation method is to transform the name of the class library into a file name and then find the file from the file system and read the content. (For the definition of the library loader, see References 2.)
All Java virtual machines include a built-in class library loader. This built-in class library loader is called a primary library loader. The special thing of the main library loader is that it can only load the class known at the design time, so the virtual machine is trusted by the classes loaded by the main class loader, and can be directly run without safety certification. . When the application needs to be loaded at the design time unknown class library, you must use a user-defined class library loader.
A user-defined class library loader is a derived class of abstract class java.lang.classloader, where the abstraction method that must be implemented is loadClass (). In general, the loadclass () method needs to be implemented as follows:
Confirm that the class library name checks whether the requested class library has been loaded with the checkup request load class library is the system class library attempts to obtain the selected class library from the class library loader to get the customized class. The library parses the requested class library returns the requested class library
A user-custom class library loader can load class libraries from any storage device. The class library loaded on the local hard drive is of course not in the words, and the library on the super connection is also easy. Due to the existence of the library loader, Java virtual machines do not need to know any details about the class library that will run in advance. Since the functionality of the library loader is so powerful, some Java class libraries such as Applets are not allowed to enable custom class library loaders.
Reference 3 gives a more detailed description of the user-defined class library while providing an example program SimpleClassLoader. In the example below herein, SimpleClassLoader in this document is used as a user-defined class library loader.
In the runtime update function module In dynamic link library technology, the LoadLibrary function is responsible for loading the function module, and the FreeELibrary function is responsible for uninstalling the function module. The new functional module is the same name with the old function module, the new dynamic link library file is also the same name with the old dynamic link library file. When you need to update a functional module, use the new dynamic link library file to replace the old dynamic link library file, the memory space occupied by the old function module is also released. However, Java does not provide a function similar to the class library uninstaller (Classunloader), which can clear the loaded function module from memory. At present, most of the virtual machines use timely compile (JIT) technology, that is, a functional module is only compiled when it is first used. After the compiled executable code is placed inside, with a HashTable to do an index, its keyword is the class library name corresponding to it. When a virtual machine needs to use a functional module, it looks for the corresponding keyword to this HashTable. If the function module already exists, the virtual machine calls the compiled executable code directly from the memory, and vice versa, then call the class library loader to load new functional modules and compile. Since there is no module uninstallation function, the function module that has been loaded at runtime has always exist. When a function module is actually updated (ie .class file is replaced with new files with the same name) and needs to be reloaded, the virtual machine does not attempt to load new function modules and call the old function module directly. If you try to use the user-defined class library loader to load new functional modules, the virtual machine throws link error due to the new function module with the old function module: Linkage Error: Duplicate Class Definition.
The brain faster may have come up with the following methods:
SimpleClassLoader SCL = New SimpleClassLoader ();
Object O;
Class C;
C = SCL.LOADClass ("Somenewclass");
o = c.newinstance ();
(SOMENEWCLASS) O) .SomeClassMethod (SomeParam);
However, such a method is actually unable to be implemented. First, SomenewClass has not yet existed when the program is designed, and such a program cannot be compiled. Second, only the user-defined class library loader SimpleClassLoader can get the definition of SOMENEWCLASS, and the last line of the above programs cannot be created, so the last row of the above programs will be wrong.
Reference 3 indicates that there are two methods to solve this problem. First, the loaded module is a derived class library of a class library that the virtual machine's primary library loader has loaded. First, the module loaded is loaded with a primary library loader that has been system virtual machine. Loaded interface. The first method is usually used in the browser, for example, all applets are the derived class libraries for java.applet.applets, so there is a statement similar to the public class myclass extends applet in all Applet source code. Here we use the second method described in Reference 3, that is, the new module loaded to implement a pre-designed interface.
Declare the interface UpdatableModule as follows:
Public Interface UpdatableModule
{
Void Start (String RuntimeParam)
}
Since this interface already exists at the design time, it can be called by the virtual machine's primary library loader and the new function module to be loaded. The new function module needs to be done, just the method in this interface, for example:
Public class newmodule_1 imports updatableModule {
Void Start (String RuntimeParam)
{
System.out.Println ("this is new module 1.");
}
}
Public class newModule_2 Implements UpdatableModule
{
Void Start (String RuntimeParam)
{
System.out.println ("this is new module 2.");
}
}
At runtime, the main program requires a new function module name from the outside. Using the user-defined class library loader loads a new functional module, generate a new function module object, and then call new features by prior definition interface Method in the module. E.g:
Public Class Test
{
Public static void main (string [] args)
{
SimpleClassLoader SCL = New SimpleClassLoader ();
String runtimemodule;
Object O;
Class C;
RuntimeModule = args [0];
C = Scl.LoadClass (RuntimeModule);
o = c.newinstance ();
(UPDATABLEMODULE) O) .Start ("No parameter needed.");
}
}
Demo procedures Let's introduce a simple data acquisition and handler. The program collects current system time and outputs to a standard output device in a certain format, where data processing module (ie, data output module) can be updated at runtime. The program includes the following functional modules:
DataBuffer ------- Data Buffer Datacolector ------ Data Acquisition Module DataProcessor ------ Data Processing Module Interface PrintData_1 -------- Data Output Module, Implement Data Processing Module DataProcessor's Interface PrintData_2 -------- Data Output Module, Implement Data Processing Module DataProcessor interface TestGui ------------ Test Interface
Data Buffer DataBuffer Store Data Acquisition Module Datacollector collected by data, which provides methods for updating data and query data.
Public Class DataBuffer
{
PRIVATE STRING DATA;
// Method for updating data
Public Synchronized Void Updatedata (String S)
{
Data = S;
NotifyAll ();
}
// Query data method
Public string getdata ()
{
Return Data;
}
}
Data Acquisition Module Datacolector is a thread that collects a system time every 5 seconds and updates the data buffer DataBuffer.
Import java.util.calendar;
Public Class Datacolector Extends Thread
{
Private DataBuffer DB;
// Constructor
Public Datacollector (DataBuffer DB)
{
DB = DB;
}
/ / Collect system time and update data buffers every 5 seconds
Public void Run ()
{
While (True)
{
Try
{
Db.Updatedata (" Calendar.getInstance (). Gettime ());
Sleep (5000);} catch (interruptedexception e) {}
}
}
}
Data Processing Module Interface DataProcessor defines how the data processing module needs to be implemented.
Public Interface DataProcessor
{
// The method of implementing the data processing module is required to start processing data
Void Start (DataBuffer DB);
// Data processing module needs to be implemented, stop processing data
Void Stop ();
}
The data output module printData_1 implements the interface of the data processing module DataProcessor. The module queries the data in the data buffer DataBuffer every 3 seconds and adds it to the flag "DATA 1:" to the standard output device.
Public Class PrintData_1 Implements DataProcessor
{
Private PrintData Pd;
PRIVATE BOOLEAN RUN;
// The method of implementing the data processing module is required to start processing data
Public Void Start (DataBuffer DB)
{
Run = True;
PD = New PrintData (DB);
Pd.start ();
}
// Data processing module needs to be implemented, stop processing data
Public synchronized void stop ()
{
Run = false;
NotifyAll ();
}
/ / Threads for data processing
Class PrintData EXTENDS THREAD
{
Private DataBuffer DB;
PRIVATE STRING DATA;
// Constructor
Public PrintData (DataBuffer DB)
{
DB = DB;
}
// data processing
Public void Run ()
{
While (RUN)
{
Try
{
Data = "DATA 1:" DB.Getdata ();
System.out.println (DATA);
Sleep (3000);
} catch (interruptedexception e) {}
}
}
}
}
The data output module printData_2 implements the interface of the data processing module DataProcessor. The module queries the data in the Data Buffer DataBuffer every 2 seconds and adds it to the flag "DATA 2:" to the standard output device.
Public Class PrintData_2 Implements DataProcessor
{
Private PrintData Pd;
PRIVATE BOOLEAN RUN;
// The method of implementing the data processing module is required to start processing data
Public Void Start (DataBuffer DB)
{
Run = True;
PD = New PrintData (DB);
Pd.start ();
}
// Data processing module needs to be implemented, stop processing data
Public synchronized void stop ()
{
Run = false;
NotifyAll ();
}
/ / Threads for data processing
Class PrintData EXTENDS THREAD
{
Private DataBuffer DB;
PRIVATE STRING DATA;
// Constructor
Public PrintData (DataBuffer DB)
{
DB = DB;
}
// data processing
Public void Run ()
{
While (RUN)
{
Try
{
Data = "DATA 2:" db.getdata ();
System.out.println (DATA);
Sleep (2000);} catch (interruptedexception e) {}
}
}
}
}
Test Image Interface TestGUI Creates a simple user graphical interface. This program declares a data buffer object and launches data acquisition thread. The user can enter the data processing module name of the run time through the graphical interface, start or terminate the data processing module, and exit the application.
Import java.awt. *;
Import java.awt.event. *;
Import com.agnc.loader. *;
Public Class TestGUI Extends Frame Implements ActionListener
{
DataBuffer DB;
Datacollector DC;
TextField ClassnameText;
Object O;
// Constructor
Public TestGui ()
{
// Construct a graphical interface
Add (CreateGUI ());
AddWindowListener (New Windowadapter ()
{
Public void WINDOWCLOSIG (WindowEvent E)
{
System.exit (0);
}
});
// Start the test module
InitTest ();
}
// Construct a graphical interface
Public Panel Creategui ()
{
// Create button and text box
Button B1, B2, B3;
B1 = New Button ("Startup Data Processing Module");
B1.SetActionCommand ("1");
B1.AddActionListener (this);
B2 = New Button ("Termination Data Processing Module");
B2.SetActionCommand ("2");
B2.AddActionListener (this);
B3 = New Button ("Exit Sample Program");
B3.SetActionCommand ("3");
B3.AddActionListener (this);
ClassNameText = New TextField ("Please enter the data processing module name";
// Create a control panel
Panel guipanel = new panel ();
Guipanel.setLayout (New GridLayout (2, 2));
Guipanel.Add (b1);
Guipanel.Add (b2);
Guipanel.Add (b3);
Guipanel.add (classnametext);
Return Guipanel;
}
// Start the test module
Public void inittest ()
{
// Construct data buffer
DB = New DataBuffer ();
// Start data acquisition thread
DC = New Datacollector (DB);
Dc.start ();
}
// Event processing module
Public Void ActionPerformed (ActionEvent E)
{
String command = E.GetActionCommand ();
String name;
Class C;
IF (Command == "1")
{
// Call the new data processing module
Try
{
Name = classnametext.getText ();
SimpleClassLoader SCL = New SimpleClassLoader ();
C = SCL.LOADClass (Name);
o = c.newinstance ();
(DataProcessor) o) .start (db);} catch (exception ex) {}
}
Else IF (Command == "2")
{
// Terminate the current data processing module
(DataProcessor) o) .stop ();
o = NULL;
}
Else
{
// Exit the sample program
System.exit (0);
}
}
// test program
Public static void main (string [] args)
{
TestGui window = new testgui ();
Window.SetTitle ("OPS Commander");
Window.pack ();
WINDOW.SETVISIBLE (TRUE);
}
}
After compiling the above source code, you can run the TestGUI in the text box of the test graph interface to enter the name of the data processing module you want to run, and then click the "Start Data Processing Module" button to run the specified data processing module, click "Terminate Data Processing Module You can terminate the current data processing module. At runtime, users can prepare new data processing modules based on data processing interface DataProcessor and submit it to the sample program. Therefore, this sample program enables the function of updating the function module at runtime.
This sample program does not implement complex error handling. At runtime, the user needs to terminate the current data processing module first to start a new data processing module.
Discussions and comparison We have implemented the functionality of the program module in the runtime update. Below we will make a simple comparison with the dynamic link library in C / C .
First, the dynamic link library used by C / C is a compiled executable code, which can be executed directly by the main program. The Java class library is bytecode, and must be called executed before the virtual machine is first called before the first call. Therefore, the startup time of the Java program is longer than the startup event of the C / C program. In addition, the implementation efficiency of the Java program is generally 20% to 30% lower than the C / C program.
Second, C / C can use the Freelibrary function to release the memory space occupied by the old function module, maintain the consistency of the function module name and the dynamic link library file name, saving memory space and disk space. Java does not provide a similar library uninstallation function, the memory space occupied by the old function module is no longer used but cannot be released, so there is a considerable amount of memory is wasted.
Since the dynamic link library file is in the process of being used, the operation of the update dynamic link library file can only be performed after the function module is terminated. Java's new function module and the old function module use different file names, download and transfer new functional modules to the specified location while running the old function module. Typically, downloading and transferring files should involve disk operations with low efficiency, so the time required for dynamic link libraries to download and transfer files in practical applications may be more than the time required to compile new function modules than virtual machines. long. But if the new dynamic link library file is used in the download and transmission process, the old dynamic link library file is removed before you need to load the new function module and the new dynamic link library file is renamed, dynamic link library implementation The time required for the program is greatly shortened.
In summary, both C / C and Java can be updated in the runtime update function module. Relatively, the C / C scheme based on dynamic link library technology is more advantageous than the Java scheme based on the library loader, and should be used as the preferred implementation.
references