The implementation principle of Tomcat thermal deployment

Source: Internet
Author: User

Overview

Noun explanation: The so-called hot deployment is to upgrade the software while the application is running, without restarting the app.

For Java applications, a hot deployment is a Java class file that is updated at run time. In the process of implementing a hot deployment on a Java-based application server 类装入器扮演着重要的角色 . Most Java-based application servers, including EJB servers and servlet containers, support hot deployment. 类装入器不能重新装入一个已经装入的类,但只要使用一个新的类装入器实例,就可以将类再次装入一个正在运行的应用程序.

We know that most Web servers now support hot deployment, and for the implementation of the thermal deployment mechanism, the online speaking is not perfect, below we on the Tomcat implementation mechanism of the hot deployment, explain how it is implemented:

The Tomcat container implements a hot deployment using two mechanisms:

    1. ClassLoader overrides the custom ClassLoader to load the corresponding JSP-compiled class into the JVM.
    2. The modified class is loaded into the JVM again by dynamically modifying the byte code in memory.
ClassLoader Implementing a JSP Reload

Tomcat org.apache.jasper.servlet.JasperLoader does this by implementing a load on the JSP, and here's a test:
1. Create a new Web project and write a JSP page that prints the page's Classloader,<%system.out.print (This.getclass (). getClassLoader ()) on the JSP page;%>.
2. Start the Web server, open the JSP page, we can see the background output, the JSP ClassLoader is an instance of Jasperloader.
3. Modify the JSP, save and refresh the JSP page, see the background output again, this ClassLoader instance is not just that, that is, Tomcat through a new ClassLoader loaded the JSP again.
4. In fact, for each JSP page Tomcat uses a separate classloader to load, each time after modifying the JSP, Tomcat will use a new classloader to load it.

about how to use a custom ClassLoader to load a class here do not say, I believe that the Internet can be found, JSP is a one-time consumption, each call to the container will create a new instance, which is used to throw the kind of, but for this way of implementation is difficult to use in other cases, As now many of our projects are using singleton, especially spring engineering, in which case it is unrealistic to use the new ClassLoader to load the modified class, and the Singleton class will produce multiple instances in memory, and this way cannot change the behavior of existing instances in the current memory, of course, Tomcat did not implement the reload of the class file in this way.

Modifying the byte code of a class in memory by proxy

The class file in Tomcat is org.apache.catalina.loader. WebappClassLoader loaded, and we can do a test that is similar to the JSP test, and the test steps are not said, just the result:

In the case of a hot deployment, for the class file loaded by the ClassLoader, it's classloader始终是同一个WebappClassLoader , unless the container restarts, believe that when you finish this experiment you will no longer think that Tomcat is using a new ClassLoader to load the modified class. And for stateful instances, the properties and states that were previously owned by that instance are saved and the next time they execute with the new class logic, which is the mystery of hot deployment (in fact, each instance simply holds the state attribute of the instance, and we can see the state contained in the object by serializing the object. The final logic is still present in the class file.

The following class redefinition is done by: java.lang.instrument实现的 Specifically, refer to the relevant documentation.

Let's look at how to modify the class bytecode in memory by proxy:

The following is a simple hot deployment Proxy implementation Class (the code is coarser and there is no judgment):

import Java.lang.instrument.classfiletransformer;import Java.lang.instrument.classfiletransformer;import Java.lang.instrument.instrumentation;import Java.util.Set; Import Java.util.timer;import Java.util.treeset;public class Hotagent {protected static set<string> Clsname    S=new treeset<string> (); public static void Premain (String Agentargs, Instrumentation inst) throws Exception {Classfiletransformer T        Ransformer =new classtransform (inst);        Inst.addtransformer (transformer);        System.out.println ("Whether to support the redefinition of a class:" +inst.isredefineclassessupported ());        Timer timer=new timer ();    Timer.schedule (New Reloadtask (inst), 2000,2000); }}
import Java.lang.instrument.classfiletransformer;import Java.lang.instrument.classfiletransformer;importjava.lang.instrument.illegalclassformatexception;import  Java.lang.instrument.instrumentation;import Java.security.protectiondomain;public class ClassTransform.    Implements Classfiletransformer {private Instrumentation inst;    Protected Classtransform (Instrumentation inst) {this.inst=inst; /** * This method is called at redefineclasses or initial load, meaning it is called when class is loaded again, * and we can dynamically modify the class bytecode to implement functions like proxies, using ASM or     Javasist, * If you are familiar with bytecode, you can modify the bytecode directly. */Public byte[] transform (ClassLoader loader, String className, class<?> classbeingredefined, Pro Tectiondomain Protectiondomain, byte[] classfilebuffer) throws illegalclassformatexception {byte[] tra        nsformed = null;        HotAgent.clsnames.add (ClassName);    return null; }}
Import Java.lang.instrument.classdefinition;import Java.io.inputstream;import Java.lang.instrument.classdefinition;import Java.lang.instrument.instrumentation;import Java.util.TimerTask;    public class Reloadtask extends TimerTask {private Instrumentation inst;    Protected Reloadtask (Instrumentation inst) {this.inst=inst;           } @Override public void Run () {try{classdefinition[] cd=new classdefinition[1];           Class[] Classes=inst.getallloadedclasses (); for (Class cls:classes) {if (Cls.getclassloader () ==null| |!                Cls.getclassloader (). GetClass (). GetName (). Equals ("Sun.misc.launcher$appclassloader")) continue;                String name=cls.getname (). replaceall ("\ \", "/");                Cd[0]=new classdefinition (Cls,loadclassbytes (cls,name+ ". Class"));           Inst.redefineclasses (CD);       }}catch (Exception ex) {ex.printstacktrace (); }} private byte[] LoadClassbytes (Class cls,string clsname) throws exception{System.out.println (clsname+ ":" +cls);        InputStream Is=cls.getclassloader (). Getsystemclassloader (). getResourceAsStream (Clsname);        if (is==null) return null;        Byte[] Bt=new byte[is.available ()];        Is.read (BT);        Is.close ();    Return BT; }}

The above is the basic implementation code that requires the components to be:
1. Hotagent (pre-load)
2. Classtransform (You can modify the bytecode of class when loading class), this example does not use
3. Reloadtask (class Timer loader, the above code is for reference only)
4. Meta-inf/manifest. MF content is: (Parameter one: support class redefinition; parameter two: pre-loaded Class)

Can-redefine-classes:true
Premain-class:agent. Hotagent

5. Package the above components into a jar file (the component is complete and the test class file is written below).
6. To create a new Java project, write a Java logic class, and write a test class that invokes the method of the logical class in the testing class, let's look at the test class code:

Package Test.redefine;public  class  Bean1 {    public  void  test1 () {      System.out.println ("= = = ========================");    }}
Package Test.redefine;public  class  test {    public  static  void  main (string[] args) Throws  interruptedexception {       Bean1  c1=new  Bean1 ();       while (true) {           c1.test1 ();           Thread.Sleep ();}}}    

To run the test class:

Java–javaagent:agent.jar Test.redefine.Test

In the test class, we used a dead loop and timed the method of invoking the logical class. We can modify the method in the Bean1 implementation, will be at different times to see different output results, about the technical details also have nothing to say, I believe we can understand.

The implementation principle of Tomcat thermal deployment

Related Article

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.