V1.1
Modified the main program and called the constructor with parameters.
Package COM. ailk; import Java. lang. reflect. *; import Java. util. arraylist; import Java. util. list; import COM. ailk. dynamic. demo; public class demomain {static public void main (string ARGs []) throws exception {string progclass = "com. ailk. dynamic. demo "; // create compilingclassloader Class C = Class. forname (progclass, true, new compilingclassloader (); // demointerface I = (demointerface) C. newinstance (); // cl1 and Chlorine is two different classloader cl1 = C. getclassloader (); classloader Cl2 = demo. class. getclassloader (); classloader l3 = demointerface. class. getclassloader (); int II = 0; List <demointerface> objlist = new arraylist (); While (true) {II ++; compilingclassloader CCL = new compilingclassloader (); // load the main function class through CCL. Class CLAS = CCL. loadclass (progclass, true); try {constructor C1 = C. getdeclaredconstructor (new class [] {string. class}); c1.setaccessible (true); demointerface a1 = (demointerface) c1.newinstance (new object [] {"Demo"});} catch (nosuchmethodexception e) {system. out. println ("the constructor does not exist"); E. printstacktrace ();} demointerface instance = NULL; try {constructor C0 = Clas. getdeclaredconstructor (); c0.setaccessible (true ); Instance = (demointerface) c0.newinstance ();} catch (nosuchmethodexception e) {system. out. println ("the constructor does not exist"); E. printstacktrace ();} CCL = NULL; // here we will take the initiative to release the service. // demointerface instance = (demointerface) Clas. newinstance (); If (instance! = NULL) {objlist. Add (instance); instance. Print ("Demo"); // call its function and PASS Parameters Using Reflection. // Generate a class object that represents the parameter type of the main function. Class mainargtype [] = {string. Class}; // find a function in the class. Method method = Clas. getmethod ("print", mainargtype); object [] argsarray = {"Demo"}; // call the method. Method. invoke (instance, argsarray);} If (II> 20) {II = 0; objlist. clear ();} thread. sleep (500); // force GC. Only compilingclassloader instances are released after the objlist is cleared. // Only when all the instances of the class loaded by compilingclassloader are released can compilingclassloader be released system. GC ();}}}
V1.0
Dynamically compile and reload the class during the running process
Classloader must be inherited, and no different compilingclassloader
The loaded classes are different and cannot be converted to each other.
For compilingclassloader instances, simply assigning null is automatically released. Only when all instances of the class loaded by compilingclassloader are released,
Compilingclassloader instances are released.
I addedProtected VoidFinalize ()To detect when an instance is released.
Put a Java program to be dynamically reloaded in reload/COM/ailk/dynamic. Here we put the test class in this directory.
Proxy
PackageCom. ailk;
Public InterfaceDemointerface {
Public VoidPrint (string ARGs );
}Test class
PackageCom. ailk. Dynamic;
ImportCom. ailk. demointerface;
Public ClassDemoImplementsDemointerface {
@ Override
Public VoidPrint (string ARGs ){
}
}
Main Program
PackageCom. ailk;
ImportJava. Lang. Reflect .*;
ImportJava. util. arraylist;
ImportJava. util. List;
ImportCom. ailk. Dynamic. Demo;
Public ClassDemomain {
Static Public VoidMain (string ARGs [])ThrowsException {
String progclass = "com. ailk. Dynamic. Demo ";
// Create compilingclassloader
Class C = Class. forname (progclass, true,NewCompilingclassloader ());
Demointerface I = (demointerface) C. newinstance ();
// Cl1 and Cl2 are two different classloader
Classloader cl1 = C. getclassloader ();
Classloader Cl2 = demo.Class. Getclassloader ();
Classloader l3 = demointerface.Class. Getclassloader ();
IntII = 0;
List <demointerface> objlist =NewArraylist ();
While(True ){
II ++;
Compilingclassloader CCL =NewCompilingclassloader ();
// Load the main function class through CCL.
Class CLAS = CCL. loadclass (progclass, true );
// Call its functions and transmit Parameters Using Reflection.
// Generate a class object that represents the parameter type of the main function.
Class mainargtype [] = {string.Class};
// Find a function in the class.
Method method = Clas. getmethod ("print", mainargtype );
Object [] argsarray = {"Demo "};
// Call the method.
Method. Invoke (CLAS. newinstance (), argsarray );
CCL = NULL; // here we will take the initiative to release
Demointerface instance = (demointerface) Clas. newinstance ();
Objlist. Add (instance );
Instance. Print ("Demo ");
If(II> 20)
{
II = 0;
Objlist. Clear ();
}
Thread. Sleep (500 );
// Force GC. The compilingclassloader instance is released only after the objlist is cleared.
// The compilingclassloader can be released only when all the instances of the class loaded by compilingclassloader are released.
System. GC ();
}
}
}
The following class is our own compilingclassloader. Its function is to load the class file from the reload of the directory in the current class path. If its Java file is updated, recompile it and load it again. Note, only the classes that need to be reloaded are put in the reload directory, and other classes should not be put in this directory, especially the proxy interface.
If the proxy interface is also placed in the corresponding directory in this directory, compilingclassloader will load it, then we willDemointerface instance = (demointerface) Clas. newinstance ()This will happen Java. Lang. classcastexceptionError.
Package com. ailk; import java. Io. *;/* compilingclassloader dynamically compiles Java source files. It checks whether the. Class file exists and whether the. Class file is earlier than the source file. */Public class compilingclassloader extends classloader {protected void finalize () {system. out. println ("finalize this:" + this); try {super. finalize ();} catch (throwable e) {// todo auto-generated catch blocke. printstacktrace () ;}// specify a file name, read the entire file content from the disk, and return a byte array. Private byte [] getbytes (string filename) throws ioexception {// get the file size. File file = new file (filename); long Len = file. Length (); // create an array to store the file content. Byte Raw [] = new byte [(INT) Len]; // open the file fileinputstream fin = new fileinputstream (File); // read all the content. If it cannot be read, indicates an error has occurred. Int r = fin. Read (raw); If (R! = Len) throw new ioexception ("can't read all," + R + "! = "+ Len); // do not forget to close the file. Fin. Close (); // returns this array. Return raw;} // generate a process to compile the specified Java source file and specify the file parameter. If the compilation is successful, true or no is returned. // return false. Private Boolean compile (string javafile) throws ioexception {// displays the current progress system. out. println ("CCL: Compiling" + javafile + "... "); // start the compiler PROCESS p = runtime.getruntime(cmd.exe C (" javac-classpath "+ compilingclassloader. class. getresource ("/"). getpath () + "-xlint: unchecked" + javafile); // wait until compilation ends. Try {P. waitfor ();} catch (interruptedexception IE) {system. out. println (IE);} // check the return code to see if the compilation has failed. Int ret = P. exitvalue (); // returns whether the compilation is successful. Return ret = 0;} // The core code of the Class Loader-automatically compile the source file when needed. Public class loadclass (string name, Boolean resolve) throws classnotfoundexception {// If (! Name. startswith ("com. ailk. Dynamic") {// return getparent (). loadclass (name); //} // Our goal is to obtain a class object. Class CLAS = NULL; // first, check whether this class has been handled. Clas = findloadedclass (name); If (CLAS! = NULL) return CLAS; // If (CLAS = NULL) {// try {// If (getparent ()! = NULL) {// CLAS = super. findclass (name); //} else {// CLAS = findsystemclass (name); //} catch (classnotfoundexception e) {// if still not found, then invoke findclass in order /// to find the class. /// CLAS = findclass (name); //} // system. out. println ("findloadedclass:" + CLAS); // obtain the path name using the class name, for example, Java. lang. object => JAVA/lang/objectstring filestub = Name. replace ('. ','/'); // construct the object pointing to the source file and class file. String javafilename = compilingclassloader. class. getresource ("/"). getpath () + "reload/" + filestub + ". java "; // system. out. println (javafilename); string classfilename = compilingclassloader. class. getresource ("/"). getpath () + "reload/" + filestub + ". class "; // system. out. println (classfilename); file javafile = new file (javafilename); file classfile = new file (classfilename); // system. out. println ("J" + Java File. lastmodified () + "C" // + classfile. lastmodified (); // first, determine whether compilation is required. If the source file exists and the class file does not exist or both exist, but the source file // is newer, it indicates that compilation is required. Boolean javaexists = javafile. exists (); Boolean classexists = classfile. exists (); If (javafile. exists ()&&(! Classfile. exists () | javafile. lastmodified ()> classfile. lastmodified () {try {// compile. If the compilation fails, we must declare the cause of the failure (it is not enough to use the obsolete Class only ). If (! Compile (javafilename) |! Classfile. exists () {Throw new classnotfoundexception ("compile failed:" + javafilename) ;}} catch (ioexception IE) {// Io errors may occur during compilation. Throw new classnotfoundexception (ie. tostring () ;}// make sure that the original bytes have been correctly compiled or do not need to be compiled. Let's start loading the original bytes. Try {// read byte. Byte Raw [] = getbytes (classfilename); // convert to Class Object CLAS = defineclass (name, raw, 0, raw. length); system. out. println ("load class:" + classfilename + "classloader is:" + this);} catch (ioexception IE) {// This does not indicate a failure, classes we may process may be in local class libraries, such as Java. lang. object .} // System. Out. println ("defineclass:" + CLAS); // It may be loaded in the class library by default. If (CLAS = NULL) {CLAS = findsystemclass (name); // system. out. println ("use define class:" + name);} // system. out. println ("findsystemclass:" + CLAS); // If the resolve parameter is true, the class is interpreted as needed. If (resolve & CLAS! = NULL) resolveclass (CLAS); // if the class has not been obtained, it indicates that the error has occurred. If (CLAS = NULL) throw new classnotfoundexception (name); // otherwise, this class object is returned. Return CLAS ;}}