Tomcat负责Web应用的类加载的是org.apache.catalina.loader.WebappClassLoader,它有几个比较重要的方法:findClass(),loadClass(),findClassInternal(),findResourceInternal().
WebappClassLoader类加载器被用来加载一个类的时候,loadClass()会被调用,loadClass()则调用findClass()。后两个方法是WebappClassLoader的私有方法,findClass()调用findClassInternal()来创建class对象,而findClassInternal()则需要findResourceInternal()来查找.class文件。
通常自己实现类记载器只要实现findclass即可,这里为了实现特殊目的而override了loadClass().
下面是精简过的代码(去除了几乎全部关于log、异常和安全控制的代码):
loadClass:
|
public
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) 再从parent的缓存中查找
clazz
= findLoadedClass(name);
if
(clazz !=
null) {
if
(resolve) resolveClass(clazz);
return
(clazz);
}
//
(0.2) 缓存中没有,则首先使用system类加载器来加载
clazz =
system.loadClass(name);
if (clazz !=
null) {
if
(resolve) resolveClass(clazz);
return
(clazz);
} //判断是否需要先让parent代理
boolean
delegateLoad = delegate ||
filter(name);
//
(1) 先让parent加载,通常delegateLoad ==
false,即这一步不会执行
if
(delegateLoad) {
ClassLoader
loader = parent;
if
(loader ==
null)
loader
= system;
clazz
= loader.loadClass(name);
if
(clazz !=
null) {
if
(resolve) resolveClass(clazz);
return
(clazz);
}
}
//
(2) delegateLoad == false 或者 parent加载失败,调用自身的加载机制
clazz
= findClass(name);
if
(clazz !=
null) {
if
(resolve) resolveClass(clazz);
return
(clazz);
}
//
(3) 自己加载失败,则请求parent代理加载
if
(!delegateLoad) {
ClassLoader
loader = parent;
if
(loader ==
null)
loader
= system;
clazz
= loader.loadClass(name);
if
(clazz !=
null) {
return
(clazz);
}
}
throw
new ClassNotFoundException(name);
}
|
findClass:
|
public Class findClass(String
name) throws ClassNotFoundException {
//
先试图自己加载类,找不到则请求parent来加载
//
注意这点和java默认的双亲委托模式不同
Class
clazz = null;
clazz
= findClassInternal(name);
if
((clazz ==
null) &&
hasExternalRepositories)
{
synchronized
(this)
{
clazz
= super.findClass(name);
}
}
if
(clazz ==
null) {
throw
new ClassNotFoundException(name);
}
return
(clazz);
}
|
加载中,请稍候......