关系图
源码分析
//构造函数
public WebappClassLoader(ClassLoader parent) {
super(new URL[0], parent);
//双亲委派
this.parent = getParent();
system = getSystemClassLoader();
securityManager = System.getSecurityManager();
if (securityManager != null) {
refreshPolicy();
}
}
//tomcat热部署的重点实现代码
//loader不同,对相同的class文件的加载产生不同点类
//热部署的时候通过loader的整体替换,达到热部署的目的
//被loadClass调用
public Class findClass(String name) throws ClassNotFoundException {
//是否由父类来加载classes
Class clazz = null;
try {
//优先自己加载
if ((clazz == null)) {
clazz = findClassInternal(name);
}
//自己加载不成功时父类加载
if ((clazz == null) && hasExternalRepositories && !searchExternalFirst) {
clazz = super.findClass(name);
}
//否则抛异常
if (clazz == null) {
throw new ClassNotFoundException(name);
}
} catch (ClassNotFoundException e) {
throw e;
}
return (clazz);
}
public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
Class clazz = null;
// (0) 检测自己的加载的缓存
clazz = findLoadedClass0(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (0.1) 检测父类的加载的缓存
clazz = findLoadedClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (0.2) 缓存中没有,则首先使用system类加载器来加载
try {
clazz = system.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
// Ignore
}
// 判断是否需要先让parent代理
boolean delegateLoad = delegate || filter(name);
// (1) parent先加载
if (delegateLoad) {
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
// (2) 以JDK推荐的方法加载类,自己重写的findClass方法,先自己加载,再父loader加载
try {
clazz = findClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
// (3) 自己无法加载或者加载失败,请求parent加载
if (!delegateLoad) {
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
//递归至父loader加载
clazz = loader.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
throw new ClassNotFoundException(name);
}
//从ClassLoader继承过来的方法
protected final Class<?> findLoadedClass(String name) {
if (!checkName(name))
return null;
return findLoadedClass0(name);
}
private native final Class findLoadedClass0(String name);
//WebappClassLoader类的方法
protected Class findLoadedClass0(String name) {
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
if (entry != null) {
return entry.loadedClass;
}
return (null); // FIXME - findLoadedResource()
}
类缓存
tomcat之所以采用自定义类装载器,除了不同应用之间有相同类不好解决之外,还有一个原因是可以缓存类以提高速度。每个由webappclassloader装载的类被视为资源,用ResourceEntry表示。加入缓存的代码是在loadclass方法中完成的,前面提到会搜索本地仓库,就是在这步调用了findClass方法完成了类的查找,并把找到的类封装成ResourceEntry,最后把这个resourceEntry放入resourceEntries中缓存起来。