当前位置:首页 > 开发 > 系统架构 > 架构 > 正文

Tomcat 5.0.18 ClassLoader source code insight

发表于: 2015-07-13   作者:DavyJones2010   来源:转载   浏览:
摘要: All the functionality of ClassLoader is nested in org.apache.catalina.loader.WebappClassLoader 1) Structure of WebappClassLoader public class WebappClassLoader extends URLClassLoader

All the functionality of ClassLoader is nested in org.apache.catalina.loader.WebappClassLoader

1) Structure of WebappClassLoader

public class WebappClassLoader
    extends URLClassLoader
    implements Lifecycle{
  /**
     * The cache of ResourceEntry for classes and resources we have loaded,
     * keyed by resource name.
     */
    protected HashMap resourceEntries = new HashMap();
    /**
     * The list of not found resources.
     */
    protected HashMap notFoundResources = new HashMap();
    public Class loadClass(String name, boolean resolve);
    protected Class findLoadedClass0(String name);
    public Class findClass(String name);
    protected Class findClassInternal(String name);

    // This method is derived from java.lang.ClassLoader; it will invoke native method searching JVM for classes loaded by current class loaders
    // It will return the loaded class if and only if the class is previously loaded(call defineClass method) by current class loader instance
    protected final Class<?> findLoadedClass(String name);
    // This method is derived from java.lang.ClassLoader, it will invoke native method  and it is the only way of converting byte[] into Class<?>; even if in our self defined ClassLoader.
    protected final Class<?> defineClass(String name, byte[] b, int off, int len,
                                         ProtectionDomain protectionDomain);
}

2) Overrides loadClass() on URLClassLoader

public Class loadClass(String name, boolean resolve){
  // (0) Check local class cache
  clazz = findLoadedClass0(name);
  if (clazz != null) {
      return (clazz);
  }
  // (0.1) Check ClassLoader inherent cache, call native method
  clazz = findLoadedClass(name);
  if (clazz != null) {
      return (clazz);
  }

  // Here we can guarantee that target class hasn't been loaded by WebAppClassLoader before, but whether it has been loaded by System/Ext/Bootstrap ClassLoader is unknown
  // Try to find class from bootstrap/ext/system ClassLoader's inherent cache, if cannot find, try to load .class from class path; throw exception when cannot be load either
  try {
       clazz = system.loadClass(name);
       return (clazz);
   } catch (ClassNotFoundException e) {
        // Ignore
   }

  // Here we are sure that the target class hasn't loaded by current application before.
  // We will try to load it from container's WEB-INF/libs

  // delegateLoad means WebappClassLoader will use parent first model, if false, means WebappClassLoader will use child first model.
  boolean delegateLoad = delegate || filter(name);

  // load class with parent
  if (delegateLoad) {
    try{
      clazz = parent.loadClass(name);
      if (clazz != null) {
         return (clazz);
      }
    }catch(ClassNotFoundException e){
      // swallow e
    }
  }
  // load class with child(It is the end of parent delegation, and it is the start of child first)
  try {
      clazz = findClass(name);
      if (clazz != null) {
          return (clazz);
      }
  } catch (ClassNotFoundException e) {
      ;
  }

  // load class with parent(It is then end of child first model)
  if (!delegateLoad) {
      ClassLoader loader = parent;
      try {
         clazz = loader.loadClass(name);
          if (clazz != null) {
              return (clazz);
          }
      } catch (ClassNotFoundException e) {
          ;
      }
  }
  // All possible tries has failed, throw exception
  throw new ClassNotFoundException(name);
}

// get class from WebappClassLoader customized class cache
protected Class findLoadedClass0(String name) {
  ResourceEntry entry = (ResourceEntry) resourceEntries.get(name);
  if (entry != null) {
        return entry.loadedClass;
  }
  return (null);  // FIXME - findLoadedResource()
}

3) How tomcat class reload works? Take a look at WebappClassLoader.stop()/start() as it implements interface Lifecycle;

// All ClassLoader did is clear its local class cache because we do not have the access to inherited java.lang.ClassLoader's inherent cache.
// reload is realized by calling stop() and start(), then loadClass() loading all classes under WEB-INF/lib
// loadClass(name) will first check local class cache which will return null, then it will check inherent cache, that would return "null" because 
// every time we restart, our WebappClassLoader is newly instantiated(the old instance is discarded)
public void stop(){
  started = false;
  notFoundResources.clear();
  resourceEntries.clear();
  repositoryURLs = null;
}
public void start() throws LifecycleException {
  started = true;
}

   The logic where a new WebappClassLoader instance is created every time the container is restarted:

// WebappLoader
public void start(){
  classLoader = createClassLoader();
  classLoader.setResources(container.getResources());
  classLoader.setDebug(this.debug);
  classLoader.setDelegate(this.delegate);
  // ...
  if (classLoader instanceof Lifecycle)
    ((Lifecycle) classLoader).start();
}
/**
* Create associated classLoader.
*/
private WebappClassLoader createClassLoader()
  throws Exception {
  Class clazz = Class.forName(loaderClass);
  WebappClassLoader classLoader = null;

  if (parentClassLoader == null) {
    parentClassLoader = Thread.currentThread().getContextClassLoader();
  }
  Class[] argTypes = { ClassLoader.class };
  Object[] args = { parentClassLoader };
  Constructor constr = clazz.getConstructor(argTypes);
  classLoader = (WebappClassLoader) constr.newInstance(args);

  return classLoader;
}

 

 

Summary:

1) We do not have direct access to native class cache defined by JVM. But we can make a little tweaks to realize class loading:

    1> We can suppose the native class cache keeps a map of Map<String, Class> with key of ClassLoader.instance.hashCode[classname+instancecode], and value of loaded class.

    2> The class would be recorded into native cache when the class loader's instance calls defineClass(), and the cached class would be returned only when current class loader instance calls findLoadedClass0();

 

Tomcat 5.0.18 ClassLoader source code insight

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号