WebappClassLoader 继承了URLClassLoader里面加入缓存和安全。
缓存:
1.缓存了已经事先装载的Classes。
2.缓存了错误信息,比如先前装载一个类报错,那么下次再load这个类的时候,就会到缓存中去查找
( ClassNotFoundException )
/** * Load the class with the specified name. This method searches for * classes in the same manner as <code>loadClass(String, boolean)</code> * with <code>false</code> as the second argument. * * @param name Name of the class to be loaded * * @exception ClassNotFoundException if the class was not found */ public Class loadClass(String name) throws ClassNotFoundException { return (loadClass(name, false)); } /** * Load the class with the specified name, searching using the following * algorithm until it finds and returns the class. If the class cannot * be found, returns <code>ClassNotFoundException</code>. * <ul> * <li>Call <code>findLoadedClass(String)</code> to check if the * class has already been loaded. If it has, the same * <code>Class</code> object is returned.</li> * <li>If the <code>delegate</code> property is set to <code>true</code>, * call the <code>loadClass()</code> method of the parent class * loader, if any.</li> * <li>Call <code>findClass()</code> to find this class in our locally * defined repositories.</li> * <li>Call the <code>loadClass()</code> method of our parent * class loader, if any.</li> * </ul> * If the class was found using the above steps, and the * <code>resolve</code> flag is <code>true</code>, this method will then * call <code>resolveClass(Class)</code> on the resulting Class object. * * @param name Name of the class to be loaded * @param resolve If <code>true</code> then resolve the class * * @exception ClassNotFoundException if the class was not found */ public 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) Check our previously loaded local class cache //在这里装载的时候使用了缓存,注意这个是local class clazz = findLoadedClass0(name); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Returning class from cache"); if (resolve) resolveClass(clazz); return (clazz); } // (0.1) Check our previously loaded class cache //而这个就是class clazz = findLoadedClass(name); if (clazz != null) { if (log.isDebugEnabled()) log.debug(" Returning class from cache"); if (resolve) resolveClass(clazz); return (clazz); } // (0.2) Try loading the class with the system class loader, to prevent // the webapp from overriding J2SE classes try { clazz = system.loadClass(name); if (clazz != null) { if (resolve) resolveClass(clazz); return (clazz); } } catch (ClassNotFoundException e) { // Ignore } // (0.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); } } } boolean delegateLoad = delegate || filter(name); // (1) Delegate to our parent if requested //代理装载类 if (delegateLoad) { if (log.isDebugEnabled()) log.debug(" Delegating to parent classloader1 " + 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) { ; } } // (2) Search local repositories 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) Delegate to parent unconditionally 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是如何从缓存中装载的
/**
* Finds the class with the given name if it has previously been
* loaded and cached by this class loader, and return the Class object.
* If this class has not been cached, return <code>null</code>.
*
* @param name Name of the resource to return
*/
protected Class findLoadedClass0(String name) {
//resouceEntries是个hashmap
ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
if (entry != null) {
return entry.loadedClass;
}
return (null); // FIXME - findLoadedResource()
}
//看看缓存对象的代码
import java.net.URL;
import java.security.cert.Certificate;
import java.util.jar.Manifest;
/**
* Resource entry.
*
* @author Remy Maucherat
* @version $Revision: 302726 $ $Date: 2004-02-27 15:59:07 +0100 (ven., 27 f茅vr. 2004) $
*/
public class ResourceEntry {
/**
* The "last modified" time of the origin file at the time this class
* was loaded, in milliseconds since the epoch.
*/
public long lastModified = -1;
/**
* Binary content of the resource.
*/
public byte[] binaryContent = null;
/**
* Loaded class.
*/
public Class loadedClass = null;
/**
* URL source from where the object was loaded.
*/
public URL source = null;
/**
* URL of the codebase from where the object was loaded.
*/
public URL codeBase = null;
/**
* Manifest (if the resource was loaded from a JAR).
*/
public Manifest manifest = null;
/**
* Certificates (if the resource was loaded from a JAR).
*/
public Certificate[] certificates = null;
}
安全机制
/** * The set of trigger classes that will cause a proposed repository not * to be added if this class is visible to the class loader that loaded * this factory class. Typically, trigger classes will be listed for * components that have been integrated into the JDK for later versions, * but where the corresponding JAR files are required to run on * earlier versions. */ protected static final String[] triggers = { "javax.servlet.Servlet" // Servlet API }; //这个在Tomcat4中有,在tomcat6.0中没有 private static final String[] packageTriggers = { "javax", // Java extensions "org.xml.sax", // SAX 1 & 2 "org.w3c.dom", // DOM 1 & 2 "org.apache.xerces", // Xerces 1 & 2 "org.apache.xalan" // Xalan };