|
一、WebappClassLoader覆盖了classloader的loadclass方法
public synchronized Class loadClass(String name, boolean resolve)
throws ClassNotFoundException {
if (log.isDebugEnabled())
log.debug("loadClass(" + name + ", " + resolve + ")");
Class clazz = null;
// Log access to stopped classloader
if (!started) {
try {
throw new IllegalStateException();
} catch (IllegalStateException e) {
log.info(sm.getString("webappClassLoader.stopped", name), e);
}
}
// (0) 检查自身缓存:WebappClassLoader之前是否已经load过这个资源
clazz = findLoadedClass0(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (1) 检查上一级缓存:ClassLoader之前是否已经load过
clazz = findLoadedClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Returning class from cache");
if (resolve)
resolveClass(clazz);
return (clazz);
}
// (2) 先交由系统ClassLoader,因此WEB-INF/lib和WEB-INF/classes或{tomcat}/libs下的类定义不能覆盖JVM 底层能够查找到的定义(譬如不能通过定义java.lang.Integer替代底层的实现
try {
clazz = system.loadClass(name);
if (clazz != null) {
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
// Ignore
}
// (5) Permission to access this class when using a SecurityManager,检查是否允许载入该类,如果该类禁止载入则抛异常
if (securityManager != null) {
int i = name.lastIndexOf('.');
if (i >= 0) {
try {
securityManager.checkPackageAccess(name.substring(0,i));
} catch (SecurityException se) {
String error = "Security Violation, attempt to use " +
"Restricted Class: " + name;
log.info(error, se);
throw new ClassNotFoundException(error, se);
}
}
}
//这是一个很奇怪的定义,JVM的ClassLoader建议先由parent去load,load不到自己再去load(见如上 ClassLoader部分),而Servelet规范的建议则恰好相反,Tomcat的实现则做个折中,由用户去决定(context的 delegate定义),默认使用Servlet规范的建议,即delegate=false
boolean delegateLoad = delegate || filter(name);
// (1) 先由parent去尝试加载,此处的parent是SharedClassLoader,见如上说明,如上说明,除非设置了delegate,否则这里不执行
if (delegateLoad) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader1 " + parent);
ClassLoader loader = parent;
//此处parent是否为空取决于context 的privileged属性配置,默认privileged=true,即parent为SharedClassLoader
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
// (2) 到WEB-INF/lib和WEB-INF/classes目录去搜索,细节部分可以再看一下findClass,会发现默认是先搜索WEB-INF/classes后搜索WEB-INF/lib
if (log.isDebugEnabled())
log.debug(" Searching local repositories");
try {
clazz = findClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from local repository");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
// (3) 由parent再去尝试加载一下
if (!delegateLoad) {
if (log.isDebugEnabled())
log.debug(" Delegating to parent classloader at end: " + parent);
ClassLoader loader = parent;
if (loader == null)
loader = system;
try {
clazz = loader.loadClass(name);
if (clazz != null) {
if (log.isDebugEnabled())
log.debug(" Loading class from parent");
if (resolve)
resolveClass(clazz);
return (clazz);
}
} catch (ClassNotFoundException e) {
;
}
}
throw new ClassNotFoundException(name);
}
二、WebappClassLoader定义了自己的findclass方法
public Class findClass(String name)
//调用
protected Class findClassInternal(String name)
//调用
protected ResourceEntry findResourceInternal(String name, String path) {
....
for (i = 0; (entry == null) && (i < repositoriesLength); i++) {
try {
String fullPath = repositories + path;//repositories里面只有一个值,即:WEB-INF/classes
Object lookupResult = resources.lookup(fullPath);
if (lookupResult instanceof Resource) {
resource = (Resource) lookupResult;
}
// Note : Not getting an exception here means the resource was
// found
entry = findResourceInternal(files, path);
ResourceAttributes attributes =
(ResourceAttributes) resources.getAttributes(fullPath);
contentLength = (int) attributes.getContentLength();
entry.lastModified = attributes.getLastModified();
if (resource != null) {
try {
binaryStream = resource.streamContent();
} catch (IOException e) {
return null;
}
if (needConvert) {
if (path.endsWith(".properties")) {
fileNeedConvert = true;
}
}
....
}
} catch (NamingException e) {
}
}
if ((entry == null) && (notFoundResources.containsKey(name)))//这里已经缓存了加载失败的类名字以提高性能。
return null;
JarEntry jarEntry = null;
synchronized (jarFiles) {//如果在WEB-INF/classes中没找到则在CLASSPATH中JAR里找
try {
if (!openJARs()) {
return null;
}
for (i = 0; (entry == null) && (i < jarFilesLength); i++) {
jarEntry = jarFiles.getJarEntry(path);
}
....
} |
|
|