Tomcat reload class at runtime

The things I writing is virtually a practice base on Peter M.Chen's article. You can also see here

The reloading I talking about here is reloading the modified classes directly without reloading all the web application.

OK, let's go on step by step.

1) Download the source code of your current Tomcat. Please be sure the version is the same, or the best you can download a set of Tomcat binary and source togeher. For example download the tomcat 4.1.34 in the page:
2) Create a new class which the name is DynamicClassLoader

package  org.apache.catalina.loader;

import  java.net.URL;
import  java.net.URLClassLoader;
import  java.security.CodeSource;
import  java.util. * ;

/**
 * 
@author peter
 
*/


public   class  DynamicClassLoader  extends  URLClassLoader  {

    
/* parent class loader, it's org.apache.catalina.loader.WebappClassLoader */
    
private ClassLoader parent = null;

    
/* list of already loaded classes names */
    
private List classNames = null;

    
/**
     * 
     * 
@param parent
     * 
     * here isorg.apache.catalina.loader.WebappClassLoader
     * 
     
*/


    
public DynamicClassLoader(ClassLoader parent) {

        
super(new URL[0]);

        classNames 
= new ArrayList();

        
this.parent = parent;

    }


    
/**
     * 
     * this method will call in WebappClassLoader .
     * 
     * 
     * 
     * 
@param name
     * 
     * 
@param classData
     * 
     * 
@param codeSource
     * 
     * 
@return
     * 
     * 
@throws ClassNotFoundException
     * 
     
*/


    
public Class loadClass(String name, byte[] classData, CodeSource codeSource)

    
throws ClassNotFoundException {

        
if (classNames.contains(name)) {

            
return loadClass(name);

        }
 else {

            classNames.add(name);

            
return defineClass(name, classData, 0, classData.length, codeSource);

        }


    }


    
/**
     * 
     * when a class not in classNames, let parent load it
     * 
     * 
@see java.lang.ClassLoader#loadClass(java.lang.String)
     * 
     
*/


    
public Class loadClass(String name) throws ClassNotFoundException {

        
if (!classNames.contains(name)) {

            
return parent.loadClass(name);

        }


        
return super.loadClass(name);

    }


}

3) Append the code to be the end of org.apache.catalina.loader.WebappClassLoader

     public   boolean  removeResourceEntry(String name)  {
        
if (resourceEntries.containsKey(name)) {
            resourceEntries.remove(name);
            
return true;
        }

        
return false;
    }


    
private   boolean  isReload  =   false ;

    
public   boolean  isReload()  {
        
return isReload;
    }


    
public   void  setReload( boolean  isReload)  {
        
this.isReload = isReload;
    }


    
private  DynamicClassLoader dynamicClassLoader  =   new  DynamicClassLoader( this );
    
public   void  reCreateDynamicClassLoader()  {
        dynamicClassLoader 
= new DynamicClassLoader(this);
    }

4) Find out the method findClass(String name) of WebappClassLoader. If it is private, set it to be public.

5) Find out the method findClassInternal(String name) of WebappClassLoader. Add the following line between the part of if (packageName != null) {} and CodeSource codeSource = new CodeSource(entry.codeBase, entry.certificates); :
       if  (isReload) removeResourceEntry(name);

6) Still in the method findClassInternal(String name) of WebappClassLoader,
modify

         if  ((entry  ==   null ||  (entry.binaryContent  ==   null ))

to be

if  ((entry  ==   null ||  (entry.loadedClass  ==   null   &&  entry.binaryContent  ==   null ))

 

7) Still in the method findClassInternal(String name) of WebappClassLoader,
modfiy

                 if  (entry.loadedClass  ==   null {
                    clazz 
= defineClass(name, entry.binaryContent, 0,
                                        entry.binaryContent.length, 
                                        codeSource);
                    entry.loadedClass 
= clazz;
                }
  else   {
                    clazz 
= entry.loadedClass;
                }


to be

                 if  (entry.loadedClass  ==   null {
                 
byte[] classData = new byte[entry.binaryContent.length];
                 System.arraycopy(entry.binaryContent, 
0, classData, 0, classData.length);
                 clazz 
= isReload ? dynamicClassLoader.loadClass(name, classData, codeSource) : defineClass(name, classData, 0, classData.length, codeSource);
                    entry.loadedClass 
= clazz;
                }
  else   {
                    clazz 
= entry.loadedClass;
                }

8) Compile WebappClassLoader and cope the corresponding classes to the right place of /server/lib/catalina.jar

9) Creating a new Jsp file which the name is test.jsp.
Add the the following code:

<%
ClassLoader loader 
=  (Thread.currentThread().getContextClassLoader());
Class clazz 
=  loader.getClass();
java.lang.reflect.Method setReload 
=  clazz.getMethod( " setReload " new  Class[] {boolean.class} );
java.lang.reflect.Method reCreate 
=  clazz.getMethod( " reCreateDynamicClassLoader " null );
java.lang.reflect.Method findClass 
=  clazz.getMethod( " findClass " , new  Class[] {String.class} );
reCreate.invoke(loader, 
null );
setReload.invoke(loader, 
new  Object[] {new Boolean(true)} );
Class A 
=  (Class)findClass.invoke(loader,  new  Object[] {"org.AClass"} );
setReload.invoke(loader, 
new  Object[] {new Boolean(false)} );
A.newInstance();
%>

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值