Beyond reloadable = true, dynamic overload class during Tomcat Runtime (version 5.0.28)

Source: Internet
Author: User

  1. Why write this document?

Developers who have used hibernate, spring, or other large components and have written more than 50 types of Web applications should know that when there are many classes in the system, if Tomcat reloadable = true is enabled, Tomcat stops the web app and releases the memory whenever the related file changes, and then reloads the web app. this is a huge project.

So I am always thinking that if I can only reload the functions of a few classes, it will greatly satisfy my instant debugging craze.

I posted a post on the forum last year and found that some application servers already have this function, such as Weblogic and websphere. There seems to be another cool name, called the development model. It seems that I am still ignorant.

Of course, many people develop on Tomcat, including me. I like it very much. Those application servers with large memory and high CPU consumption are worthy of being the hardware killer. There is no reason not to improve tomcat.

  1. Final Implementation Function

I don't have time to study the file listening mechanism of Tomcat, and I don't have time to write it into the full function of "development mode". What I ultimately implement is, test JSP for implementing the overload function -- sorry, I still cannot write it completely. Of course, you can make improvements on this basis.

  1. Instructions

Read this article and you should have the following knowledge

    1. JVM Specification

      Http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html

    2. Tomcat class loading mechanism

      Http://www.huihoo.org/apache/tomcat/

    3. Java reflection mechanism

      Http://java.sun.com/docs/books/tutorial/reflect/

    4. Ant

      Http://ant.apache.org/

      (It seems that the website is blocked from time to time, sometimes accessible or sometimes unavailable)

It is best to install ant on your computer, because the Tomcat source code package uses ant to obtain the dependency package from the Internet. However, I modified an error to make it fully compiled.

Of course, you can also use other ide tools to check and add dependency packages. In IDE, you only need to add the jar until org. Apache. Catalina. loader. webappclassloader has no error.

  1. Modification Process

    1. Description

Add the newly added code to the end of the Java file, because when I describe the number of lines, try to match the original number of lines

    1. Web app Class Loader

In tomcat, org. Apache. Catalina. loader. webappclassloader is the class loader of the web app, so you need to modify it to implement the overload function.

    1. Resource list

In webappclassloader, there is a map type attribute resourceentries, which records the classes loaded under the WEB-INF/classes directory in the web app, so when we need to reload a class, we need to delete it in resourceentries first. I have compiled a method to facilitate the call:

Public BooleanRemoveresourceentry (string name ){

If(Resourceentries. containskey (name )){

Resourceentries. Remove (name );

Return True;

}

Return False;

}

    1. Indicates whether to overload the flag.

Make webappclassloader need to know whether to load a class using the overload method. So I create a Boolean attribute and implement its getter/setter method:

Private BooleanIsreload =False;

Public BooleanIsreload (){

ReturnIsreload;

}

Public VoidSetreload (BooleanIsreload ){

This. Isreload = isreload;

}

    1. Dynamic Class Loader

According to the JVM Class Loader specification, a Class Loader object can only load one class once. Therefore, the overload is actually to create another class loader object to load the same class. Of course, we do not need to create another webappclassloader. It is too large and the loading rules are complicated. It is not what we want, so we create a simple Class Loader class Org. apache. catalina. loader. dynamicclassloader:

PackageOrg. Apache. Catalina. loader;

ImportJava.net. url;

ImportJava.net. urlclassloader;

ImportJava. Security. codesource;

ImportJava. util .*;

/**

* Dynamic Class Loader

*

*@ AuthorPeter

*

*/

Public ClassDynamicclassloaderExtendsUrlclassloader {

/* Parent loader */

PrivateClassloader parent =Null;

/* List of loaded class names */

PrivateList classnames =Null;

/**

* Constructor

*

*@ ParamParent

* The parent class loader. The input here is webappclassloader.

*/

PublicDynamicclassloader (classloader parent ){

Super(NewURL [0]);

Classnames =NewArraylist ();

This. Parent = parent;

}

/**

* Load a class from the binary data of the class.

*

*@ ParamName

* Class Name

*@ ParamClassdata

* Binary data of the class

*@ ParamCodesource

* Data Source

*@ ReturnSuccessfully loaded class

*@ ThrowsClassnotfoundexception

* An error occurred while loading. This type of exception is not found.

*/

PublicClass loadclass (string name,Byte[] Classdata, codesource)ThrowsClassnotfoundexception {

If(Classnames. Contains (name )){

// System. Out. println ("this class already exists. Call the loadclass method to load .");

ReturnLoadclass (name );

}Else{

// System. Out. println ("New Class, record to the class name list, and load the class using the class definition method ");

Classnames. Add (name );

ReturnDefineclass (name, classdata, 0, classdata. length, codesource );

}

}

/**

* This method is reloaded. When the class to be loaded is not in the class name list, the parent class loader method is called for loading.

* @ See java. Lang. classloader # loadclass (Java. Lang. String)

*/

PublicClass loadclass (string name)ThrowsClassnotfoundexception {

If(! Classnames. Contains (name )){

// System. Out. println ("the parent classloader method is called to load the table without class names ");

ReturnParent. loadclass (name );

}

Return Super. Loadclass (name );

}

}

    1. Add dynamicclassloader to webappclassloader

      1. Add attribute

PrivateDynamicclassloader =NewDynamicclassloader (This);

      1. Add the reconstruction method to replace the last class loader object when you need to reload it again.

Public VoidRecreatedynamicclassloader (){

Dynamicclassloader =NewDynamicclassloader (This);

}

    1. Modify call point

      1. Row 3: exposes the findclass method.

PublicClass findclass (string name)ThrowsClassnotfoundexception {

      1. Line 3: Add the following line of code.

If(Isreload) removeresourceentry (name );

      1. Row 3 shows a bug. I forgot the specific cause-_-|

If(Entry =Null) | (Entry. binarycontent =Null))

Change

If(Entry =Null) | (Entry. loadedclass =Null& Entry. binarycontent =Null))

      1. 1633rd ~ 1636 rows

If(Entry. loadedclass =Null){

Clazz = defineclass (name, entry. binarycontent, 0, entry. binarycontent. length,

Codesource );

Change

Byte[] Classdata =New Byte[Entry. binarycontent. Length];

System. arraycopy (entry. binarycontent, 0, classdata, 0,

Classdata. Length );

If(Entry. loadedclass =Null){

Clazz = isreload?

Dynamicclassloader. loadclass (name,

Classdata, codesource ):

Defineclass (name,

Classdata, 0, classdata. length, codesource );

    1. Test code

      1. Test. jsp

The JSP used for my test is $ catalina_home/webapps/root/test. jsp. Because the core class of Tomcat is not explicitly loaded in the webapp, we need to use the reflection code to call the webappclassloader method. The Code is as follows:

<%

Classloader loader = (thread. currentthread (). getcontextclassloader ());

Class clazz = loader. getclass ();

Java. Lang. Reflect. Method setreload = clazz. getmethod ("setreload ",NewClass [] {Boolean.Class});

Java. Lang. Reflect. Method recreate = clazz. getmethod ("recreatedynamicclassloader ",Null);

Java. Lang. Reflect. Method findclass = clazz. getmethod ("findclass ",NewClass [] {string.Class});

Recreate. Invoke (loader,Null);

Setreload. Invoke (loader,NewObject [] {True});

Class A = (class) findclass. Invoke (loader,NewObject [] {"org. Aclass "});

Setreload. Invoke (loader,NewObject [] {False});

A. newinstance ();

// If you use the following line of code, when re-compiling the class, Please modify the JSP that calls it slightly so that the JSP can be re-compiled.

// Org. Aclass A = (Org. Aclass) A. newinstance ();

// The following code is used to test the response when a class is not in the dynamicclassloader class name list.

// A. Test ();

// Java. Lang. Reflect. method test = A. getclass (). getmethod ("test", null );

// Test. Invoke (A, null );

%>

      1. Org. Aclass

PackageOrg;

Public ClassAclass {

PublicAclass (){

// Modify the output content to confirm that Tomcat reloads the class

System. Out. println ("Aclass V3 ");

}

Public VoidCreatebclass (){

NewBclass ();

}

}

      1. Org. bclass

PackageOrg;

Public ClassBclass {

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.