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); :6) Still in the method findClassInternal(String name) of WebappClassLoader,
modify
to be
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();
%>
本文介绍了一种在Tomcat中实现类文件热更新的方法,通过自定义类加载器及修改WebappClassLoader,使得可以在不重启应用的情况下更新部分类文件。
2016

被折叠的 条评论
为什么被折叠?



