Explore Java hot deployment in depth

Source: Internet
Author: User

Exploration of class loading

First of all, what is hot deployment (HOTSWAP), a hot deployment is the ability to automatically detect changes to a class file without restarting the Java virtual machine, updating the behavior of the runtime class. Java classes are loaded by a Java virtual machine, and a class file is ClassLoader loaded, the corresponding class object is generated, and then an instance of the class is created. The default virtual machine behavior only loads the class at startup, and if a later class needs to be updated, simply replacing the compiled class file, the Java virtual machine will not update the running class. If you want to implement a hot deployment, the most fundamental way is to modify the virtual machine's source code, change the load behavior of the ClassLoader, so that the virtual function listens to the class file update, reload the class file, this behavior is very destructive, for the subsequent JVM upgrade buried a big pit.

Another friendly approach is to create your own classloader to load the class that needs to be monitored, so that you can control when the classes are loaded, allowing for a hot deployment. This article will specifically explore how to implement this scenario. The first step is to understand the existing loading mechanism of the Java virtual machine. The current loading mechanism, called parental delegation, asks the current ClassLoader parent class if it is capable of loading, and if the parent class cannot implement the load operation, the task will be classloader to the ClassLoader to load. The benefit of this top-down loading method is that each classloader performs its own load task and does not load the class repeatedly. But this makes the loading order very difficult to change, so that custom ClassLoader preemptive loading of classes that need to listen for changes becomes a challenge.

But we can change the idea, although we can't get the first load of the class, but you can still create a class with the same functionality as the custom ClassLoader, so that each instantiated object points to the new class. When the class file changes, create an updated class again, and then if the system makes an instantiation request again, the created object points to the new class.

Here's a brief list of what needs to be done.

    • Create a custom ClassLoader, load the class that needs to listen for changes, and reload the class file when it changes.

    • Change the behavior of the created objects so that they are created with the custom ClassLoader loaded class.

Back to top of page

Implementation of the custom loader

The custom loader still needs to perform the function of class loading. There is a problem here, the same ClassLoader cannot load two classes of the same name at the same time, because no matter how the structure of the class changes, the generated class name does not change, and ClassLoader can only destroy the loaded class before the virtual machine stops, so ClassLoader cannot load the updated class. Here's a little trick to keep each loaded class stored as a type with version information, like when loading Test.class, the class stored in memory is Test_v1.class, and when the class changes, the reload class name is Test_v2.class. But the DefineClass method that actually executes the load class file to create the class is a native method that becomes difficult to modify. So there is still a road ahead, that is, directly modify the compiled generated class file.

Modifying class files with ASM

There are many frameworks that can modify bytecode, such as Asm,cglib. This article uses ASM. First to introduce the structure of class file, class file contains the following types of information, one is the basic information of the class, including access rights information, class name information, parent information, interface information. The second one is the variable information for the class. The third one is information about the method. ASM loads a class file and then reads the class information in strict order, and the user can define the enhanced component to modify the information and then output it as a new class.

First look at how ASM can be used to modify class information.

Listing 1. Using ASM to modify byte codes
        classwriter cw = new classwriter ( CLASSWRITER.COMPUTE_MAXS);          classreader cr =  null;             String  Enhancedclassname = classsource.getenhancedname ();          try {             cr =  New classreader (New fileinputstream (                      classsource.getfile ()));          } catch  (ioexception e)  {              e.printstacktrace ();              return null;         }          classvisitor cv = new enhancedmodifier (cw,                  classname.replace (".",  "/"),                   Enhancedclassname.replace (".",  "/"));          cr.accept (CV,  0);

ASM the process of modifying bytecode files is a chain of responsibility mode, first using a classreader to read the bytecode, and then use Classvisitor to make personalized changes, and finally use Classwriter output modified bytecode.

As mentioned before, the class name of the read class file needs to be modified to be loaded into a derived class with a completely new name. This is divided into 2 steps.

The first step is to turn the original class into an interface first.

Listing 2. Redefining the original class
    public class<?> redefineclass (String classname) {          classwriter cw = new classwriter ( CLASSWRITER.COMPUTE_MAXS);          classreader cr =  null;         ClassSource cs =  Classfiles.get (ClassName);          if (Cs==null) {              return null;          }         try {              cr = new classreader (New  fileinputstream (Cs.getfile ()));         } catch  ( Ioexception e)  {      &Nbsp;      e.printstacktrace ();              return null;         }          classmodifier cm = new classmodifier (CW);          cr.accept (cm, 0);          byte[] code = cw.tobytearray ();          return defineclass (classname, code, 0, code.length);   }

First load the class file of the original classes, where an enhanced component ClassModifier is defined that modifies the type of the original class and transforms it into an interface. All method logic for the original class is removed.

In the second step, the generated derived classes implement this interface, the original class, and copy all the method logic from the original class. Later, if the class needs to be updated, a new derived class is generated, and this interface is implemented. The purpose of this is to have a common interface between the derived classes of the same class, regardless of how they are modified, and the transitions between them become opaque to the outside.

Listing 3. Defining a derived class
    //  redefine this class when the  class  file changes     private Class< ? > redefineclass (String classname, classsource classsource) {          classwriter cw = new classwriter (ClassWriter.COMPUTE_MAXS);          ClassReader cr = null;          classsource.update ();          string enhancedclassname = classsource.getenhancedname ();                try {              cr = new classreader (                      new  FileInputStream (Classsource.getfiLe ()));         } catch  (ioexception e)  {              e.printstacktrace ();              return null;          }         enhancedmodifier em  = new enhancedmodifier (Cw, classname.replace (".",  "/"),                  enhancedclassname.replace (".",   "/"));          extendmodifier exm = new  extendmodifier (Em, classname.replace (".",  "/"),                  enhancedclassname.replace (".",  "/"));        &Nbsp; cr.accept (exm, 0);         byte[] code  = cw.tobytearray ();          classsource.setbytecopy (code);          class<?> clazz = defineclass ( Enhancedclassname, code, 0, code.length);          Classsource.setclasscopy (Clazz);         return clazz;   }

Load the class file of the original classes again, where two enhancements are defined, one EnhancedModifier of which is the function of the enhanced component to change the original class name. The second enhancement component is ExtendModifier that the function of this enhanced component is to change the parent class of the original class so that the modified derived class can implement the same original class (at which point the original class has been turned into an interface).

Custom ClassLoader Another function is to listen to the class file that will change, ClassLoader will manage a timer and periodically scan these class files for changes.

Back to top of page

Changing the behavior of creating objects

There are two common ways to create objects in a Java virtual machine, one that is statically created, a direct new object, a dynamic creation, and a reflection method to create an object.

Since the type of the original class has been changed in the custom loader and changed from class to interface, neither of these methods can be created. What we want to do is to instantiate the behavior of the original class into an instantiated derived class.

The first way to do this is to create it statically, change it to get the class by ClassLoader, and create the object dynamically.

Listing 4. The logic corresponding to the replaced instruction set
Original logic Greeter p = new Greeter ();  The changed logic igreeter p = (igreeter) myclassloader.getinstance (). Findclass ("Com.example.Greeter"). newinstance ();

ASM is also needed to modify the class file. Finds statements for all new objects, replaced by ClassLoader to get the form of an object.

Listing 5. Using ASM to modify the method body
@Override  public void visittypeinsn (int opcode, string type)  { if ( Opcode==opcodes.new && type.equals (className)) { list<localvariablenode>  Variables = node.localvariables; string compiletype = null; for (int i= 0;i<variables.size (); i++) { localvariablenode localvariable = variables.get (i);  Compiletype = formtype (LOCALVARIABLE.DESC);  if (MatchType (compiletype) &&! Valiableindexused[i]) { valiableindexused[i] = true; break; } }  MV.VISITMETHODINSN (opcodes.invokestatic, classload_type,      "GetInstance",   "() L" +classload_type+ ";"); &NBSP;MV.VISITLDCINSN (Type.replace ("/",  ")); &NBSP;MV.VISITMETHODINSN (opcodes.invokevirtual, classload_type,      "FindClass",   "(ljava/lang/string;) ljava/lang/class;"); &NBSP;MV.VISITMETHODINSN (opcodes.invokevirtual,  "Java/lang/class",      "Newinstance",  "() Ljava/lang/Object;"); &NBSP;MV.VISITTYPEINSN (opcodes.checkcast, compiletype);  flag = true; } else &NBSP;{&NBSP;MV.VISITTYPEINSN (opcode, type);  }  }

For the second method of creation, you need to modify Class.forName() ClassLoader.findClass() the behavior of the and so that they load the class through the custom loader.

Back to top of page

Using javaagent to intercept the behavior of the default loader

The previously implemented ClassLoader has solved the functionality required for hot deployment, but when the JVM starts, it does not load all the class files under Classpath with a custom loader, instead of loading them with the application loader. If you later load the loaded class with a custom loader, you may have linkageerror exception. You must re-replace the loaded class before the app starts. If there is only one method to use before jdk1.4, change the loading behavior of ClassLoader in the JDK to point to the load behavior of the custom loader. Fortunately, after jdk5.0, we have another aggressive smaller approach, this is the Javaagent method, Javaagent can be launched after the JVM, the application before the start of a short gap, provide space for the user to do some special behavior. The more common application is to use javaagent to do aspect-oriented programming, and to add monitoring logs to the methods.

The implementation of Javaagent is easy, as long as within a class, define a Premain method.

Listing 6. A simple javaagent.
public class Reloadagent {public static void Premain (String Agentargs, Instrumentation inst) {Generaltransfor         Mer trans = new Generaltransformer ();     Inst.addtransformer (trans); }  }

Then write a manifest file that Premain-Class sets the property to define a premain class name that owns the method.

Generate a jar package containing this manifest file.

manifest-version:1.0 premain-class:com.example.reloadagent Can-redefine-classes:true

Finally, add the parameters to the application's parameters -javaagent to add the jar. You can also Javaagent add parameters to the parameter, which is the absolute path to test project in the testing code. This will take precedence over the logic in the method before executing the application, premain and pre-parse the class that needs to be loaded.

Figure 1. Increase execution parameters

650) this.width=650; "Width=" 572 "alt=" Figure 1. Add execution parameter "src=" Http://www.ibm.com/developerworks/cn/java/j-lo-hotdeploy/image001.png "/>

JavaAgentthe substitution of the original bytecode is used here to prevent the original bytecode from being loaded by the Java virtual machine. Simply implement 一个 ClassFileTransformer the interface and use this implementation class to complete the function of class substitution.

Listing 7. Replace class
@Override public byte [] transform (ClassLoader paramclassloader, String paramstring, class<?> Paramclass, Prote Ctiondomain Paramprotectiondomain, Byte [] paramarrayofbyte) throws Illegalclassformatexception {String ClassName = Paramstring.replace ("/", "."); if (Classname.equals ("Com.example.Test")) {Myclassloader cl = myclassloader.getinstance (); Cl.definereference ( ClassName, "Com.example.Greeter"); Return Cl.getbytecode (ClassName); }else if (classname.equals ("Com.example.Greeter")) {Myclassloader cl = myclassloader.getinstance (); Cl.redefineclass ( ClassName); Return Cl.getbytecode (ClassName);  } return null; }

At this point, all the work is done, and enjoy the results of hotswap.

Figure 2. Test Execution Results

650) this.width=650; "Width=" 572 "alt=" Figure 2. Test execution Result "src=" Http://www.ibm.com/developerworks/cn/java/j-lo-hotdeploy/image002.png "/>


This article is from the "Java White Battlefield" blog, be sure to keep this source http://8023java.blog.51cto.com/10117207/1795099

Explore Java hot deployment in depth

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.