/* *
* 重载此方法,当要加载的类不在类名列表中时,调用父类加载器方法加载.
* @see java.lang.ClassLoader#loadClass(java.lang.String)
*/
public Class loadClass(String name) throws ClassNotFoundException {
if (!classNames.contains(name)) {
//System.out.println("不在类名列表中,调用父类加载器方法加载");
return parent.loadClass(name);
}
return super.loadClass(name);
}
}
在webappClassLoader中添加DynamicClassLoader
添加属性
private DynamicClassLoader dynamicClassLoader = new DynamicClassLoader(this);
添加重建方法,以便需要再次重载时替换掉上次的类加载器对象
public void reCreateDynamicClassLoader() {
dynamicClassLoader = new DynamicClassLoader(this);
}
修改调用点
第832行,公开findClass方法
public Class findClass(String name) throws ClassNotFoundException {
第1569行,添加如下一行代码。
if (isReload) removeResourceEntry(name);
第1577行,这里好像是一个bug,具体原因我忘了-_-||
if ((entry == null) || (entry.binaryContent == null))
改为
if ((entry == null) || (entry.loadedClass == null && entry.binaryContent == null))
第1633~1636行
if (entry.loadedClass == null) {
clazz = defineClass(name, entry.binaryContent, 0, entry.binaryContent.length,
codeSource);
改为
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);
测试代码
test.jsp
我测试用的jsp为$CATALINA_HOME/webapps/ROOT/test.jsp,由于webapp里面并不会显式加载tomcat的核心类,所以我们需要用反射代码调用WebappClassLoader的方法。代码如下:
<%
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[]{true});
Class A = (Class)findClass.invoke(loader, new Object[]{"org.AClass"});
setReload.invoke(loader, new Object[]{false});
A.newInstance();
// 如果你使用下面这行代码,当重编译类时,请稍微修改一下调用它的jsp,让jsp也重新编译
//org.AClass a = (org.AClass)A.newInstance();