`
outlaw
  • 浏览: 30667 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Tomcat ClassLoader研究

阅读更多

 Tomcat ClassLoader研究 收藏

<script type="text/javascript"></script><script type="text/javascript"></script>

http://tomcat.apache.org/tomcat-4.1-doc/class-loader-howto.html

Tomcat的ClassLoader层次结构:

      Bootstrap


          |


       System


          |


       Common


      /      \


 Catalina   Shared


             /   \


        Webapp1  Webapp2 ...

源代码如下:

org.apache.catalina.startup.Bootstrap类(tomcat主类)

 

  1. public final class Bootstrap {   
  2.     // ------------------------------------------------------- Static Variables   
  3.     /**  
  4.      * Debugging detail level for processing the startup.  
  5.      */  
  6.     private static int debug = 0;   
  7.     // ----------------------------------------------------------- Main Program   
  8.     /**  
  9.      * The main program for the bootstrap.  
  10.      *  
  11.      * @param args Command line arguments to be processed  
  12.      */  
  13.     public static void main(String args[]) {   
  14.         // Set the debug flag appropriately   
  15.         for (int i = 0; i < args.length; i++)  {   
  16.             if ("-debug".equals(args[i]))   
  17.                 debug = 1;   
  18.         }   
  19.         // Configure catalina.base from catalina.home if not yet set   
  20.         if (System.getProperty("catalina.base") == null)   
  21.             System.setProperty("catalina.base", getCatalinaHome());   
  22.         // Construct the class loaders we will need   
  23.         ClassLoader commonLoader = null;   
  24.         ClassLoader catalinaLoader = null;   
  25.         ClassLoader sharedLoader = null;   
  26.         try {   
  27.             File unpacked[] = new File[1];   
  28.             File packed[] = new File[1];   
  29.             File packed2[] = new File[2];   
  30.             ClassLoaderFactory.setDebug(debug);   
  31.             unpacked[0] = new File(getCatalinaHome(),   
  32.                                    "common" + File.separator + "classes");   
  33.             packed2[0] = new File(getCatalinaHome(),   
  34.                                   "common" + File.separator + "endorsed");   
  35.             packed2[1] = new File(getCatalinaHome(),   
  36.                                   "common" + File.separator + "lib");   
  37.             commonLoader =   
  38.                 ClassLoaderFactory.createClassLoader(unpacked, packed2, null);   
  39.             unpacked[0] = new File(getCatalinaHome(),   
  40.                                    "server" + File.separator + "classes");   
  41.             packed[0] = new File(getCatalinaHome(),   
  42.                                  "server" + File.separator + "lib");   
  43.             catalinaLoader =   
  44.                 ClassLoaderFactory.createClassLoader(unpacked, packed,   
  45.                                                      commonLoader);   
  46.             unpacked[0] = new File(getCatalinaBase(),   
  47.                                    "shared" + File.separator + "classes");   
  48.             packed[0] = new File(getCatalinaBase(),   
  49.                                  "shared" + File.separator + "lib");   
  50.             sharedLoader =   
  51.                 ClassLoaderFactory.createClassLoader(unpacked, packed,   
  52.                                                      commonLoader);   
  53.         } catch (Throwable t) {   
  54.             log("Class loader creation threw exception", t);   
  55.             System.exit(1);   
  56.         }   
  57.         Thread.currentThread().setContextClassLoader(catalinaLoader);   
  58.         // Load our startup class and call its process() method   
  59.         try {   
  60.             SecurityClassLoad.securityClassLoad(catalinaLoader);   
  61.             // Instantiate a startup class instance   
  62.             if (debug >= 1)   
  63.                 log("Loading startup class");   
  64.             Class startupClass =   
  65.                 catalinaLoader.loadClass   
  66.                 ("org.apache.catalina.startup.Catalina");   
  67.             Object startupInstance = startupClass.newInstance();   
  68.             // Set the shared extensions class loader   
  69.             if (debug >= 1)   
  70.                 log("Setting startup class properties");   
  71.             String methodName = "setParentClassLoader";   
  72.             Class paramTypes[] = new Class[1];   
  73.             paramTypes[0] = Class.forName("java.lang.ClassLoader");   
  74.             Object paramValues[] = new Object[1];   
  75.             paramValues[0] = sharedLoader;   
  76.             Method method =   
  77.                 startupInstance.getClass().getMethod(methodName, paramTypes);   
  78.             method.invoke(startupInstance, paramValues);   
  79.             // Call the process() method   
  80.             if (debug >= 1)   
  81.                 log("Calling startup class process() method");   
  82.             methodName = "process";   
  83.             paramTypes = new Class[1];   
  84.             paramTypes[0] = args.getClass();   
  85.             paramValues = new Object[1];   
  86.             paramValues[0] = args;   
  87.             method =   
  88.                 startupInstance.getClass().getMethod(methodName, paramTypes);   
  89.             method.invoke(startupInstance, paramValues);   
  90.         } catch (Exception e) {   
  91.             System.out.println("Exception during startup processing");   
  92.             e.printStackTrace(System.out);   
  93.             System.exit(2);   
  94.         }   
  95.     }  

 

其中:

commonLoader =
                ClassLoaderFactory.createClassLoader(unpacked, packed2, null);

创建common classloader,以AppClassLoader为父ClassLoader

catalinaLoader =
                ClassLoaderFactory.createClassLoader(unpacked, packed,
                                                     commonLoader);

创建catalina classloader,以common classloader为父classloader

sharedLoader =
                ClassLoaderFactory.createClassLoader(unpacked, packed,
                                                     commonLoader);

创建share classloader,以common classloader为父classloader

Thread.currentThread().setContextClassLoader(catalinaLoader);

设置ContextClassLoader为catalina classloader

org.apache.catalina.startup.ClassLoaderFactory类

 

  1. public static ClassLoader createClassLoader(File unpacked[],   
  2.                                                 File packed[],   
  3.                                                 ClassLoader parent)   
  4.         throws Exception {   
  5.         if (debug >= 1)   
  6.             log("Creating new class loader");   
  7.         // Construct the "class path" for this class loader   
  8.         ArrayList list = new ArrayList();   
  9.         // Add unpacked directories   
  10.         if (unpacked != null) {   
  11.             for (int i = 0; i < unpacked.length; i++)  {   
  12.                 File file = unpacked[i];   
  13.                 if (!file.isDirectory() || !file.exists() || !file.canRead())   
  14.                     continue;   
  15.                 if (debug >= 1)   
  16.                     log("  Including directory " + file.getAbsolutePath());   
  17.                 URL url = new URL("file"null,   
  18.                                   file.getCanonicalPath() + File.separator);   
  19.                 list.add(url.toString());   
  20.             }   
  21.         }   
  22.         // Add packed directory JAR files   
  23.         if (packed != null) {   
  24.             for (int i = 0; i < packed.length; i++) {   
  25.                 File directory = packed[i];   
  26.                 if (!directory.isDirectory() || !directory.exists() ||   
  27.                     !directory.canRead())   
  28.                     continue;   
  29.                 String filenames[] = directory.list();   
  30.                 for (int j = 0; j < filenames.length; j++) {   
  31.                     String filename = filenames[j].toLowerCase();   
  32.                     if (!filename.endsWith(".jar"))   
  33.                         continue;   
  34.                     File file = new File(directory, filenames[j]);   
  35.                     if (debug >= 1)   
  36.                         log("  Including jar file " + file.getAbsolutePath());   
  37.                     URL url = new URL("file"null,   
  38.                                       file.getCanonicalPath());   
  39.                     list.add(url.toString());   
  40.                 }   
  41.             }   
  42.         }   
  43.         // Construct the class loader itself   
  44.         String array[] = (String[]) list.toArray(new String[list.size()]);   
  45.         StandardClassLoader classLoader = null;   
  46.         if (parent == null)   
  47.             classLoader = new StandardClassLoader(array);   
  48.         else  
  49.             classLoader = new StandardClassLoader(array, parent);   
  50.         classLoader.setDelegate(true);   
  51.         return (classLoader);   
  52.     }  

 

ClassLoaderFactory创建的是StandardClassLoader(org.apache.catalina.loader包中)

由Bootstrap类调用Catalina类的process()方法,再调用execute()方法,再调用start()来启动Server实例。

当Tomcat开启每个Context时,是调用的StandardContext的start()方法,其中:

设置Loader为WebappLoader

 

  1. if (getLoader() == null) {      // (2) Required by Manager   
  2.             if (getPrivileged()) {   
  3.                 if (debug >= 1)   
  4.                     log("Configuring privileged default Loader");   
  5.                 setLoader(new WebappLoader(this.getClass().getClassLoader()));   
  6.             } else {   
  7.                 if (debug >= 1)   
  8.                     log("Configuring non-privileged default Loader");   
  9.                 setLoader(new WebappLoader(getParentClassLoader()));   
  10.             }   
  11.         }  

 

然后调用:bindThread(),设置当前线程的ClassLoader为WebappLoader的ClassLoader,即为WebappClassLoader

 

  1. private ClassLoader bindThread() {   
  2.         ClassLoader oldContextClassLoader =    
  3.             Thread.currentThread().getContextClassLoader();   
  4.         if (getResources() == null)   
  5.             return oldContextClassLoader;   
  6.         Thread.currentThread().setContextClassLoader   
  7.             (getLoader().getClassLoader());   
  8.         DirContextURLStreamHandler.bind(getResources());   
  9.         if (isUseNaming()) {   
  10.             try {   
  11.                 ContextBindings.bindThread(thisthis);   
  12.             } catch (NamingException e) {   
  13.                 // Silent catch, as this is a normal case during the early   
  14.                 // startup stages   
  15.             }   
  16.         }   
  17.         return oldContextClassLoader;   
  18.     }  

 

WebappLoader的ClassLoader的赋值如下:

 

  1. private String loaderClass =   
  2.         "org.apache.catalina.loader.WebappClassLoader";   
  3. ......   
  4. public void start() throws LifecycleException {   
  5.         // Validate and update our current component state   
  6.         if (started)   
  7.             throw new LifecycleException   
  8.                 (sm.getString("webappLoader.alreadyStarted"));   
  9.         if (debug >= 1)   
  10.             log(sm.getString("webappLoader.starting"));   
  11.         lifecycle.fireLifecycleEvent(START_EVENT, null);   
  12.         started = true;   
  13.         if (container.getResources() == null)   
  14.             return;   
  15.         // Register a stream handler factory for the JNDI protocol   
  16.         URLStreamHandlerFactory streamHandlerFactory =   
  17.             new DirContextURLStreamHandlerFactory();   
  18.         try {   
  19.             URL.setURLStreamHandlerFactory(streamHandlerFactory);   
  20.         } catch (Throwable t) {   
  21.             // Ignore the error here.   
  22.         }   
  23.         // Construct a class loader based on our current repositories list   
  24.         try {   
  25.             classLoader = createClassLoader();   
  26.             classLoader.setResources(container.getResources());   
  27.             classLoader.setDebug(this.debug);   
  28.             classLoader.setDelegate(this.delegate);   
  29.             if (container instanceof StandardContext)   
  30.                 classLoader.setAntiJARLocking(((StandardContext) container).getAntiJARLocking());   
  31.             for (int i = 0; i < repositories.length; i++) {   
  32.                 classLoader.addRepository(repositories[i]);   
  33.             }   
  34.             // Configure our repositories   
  35.             setRepositories();   
  36.             setClassPath();   
  37.             setPermissions();   
  38.             if (classLoader instanceof Lifecycle)   
  39.                 ((Lifecycle) classLoader).start();   
  40.             // Binding the Webapp class loader to the directory context   
  41.             DirContextURLStreamHandler.bind   
  42.                 ((ClassLoader) classLoader, this.container.getResources());   
  43.         } catch (Throwable t) {   
  44.             throw new LifecycleException("start: ", t);   
  45.         }   
  46.         // Validate that all required packages are actually available   
  47.         validatePackages();   
  48.         // Start our background thread if we are reloadable   
  49.         if (reloadable) {   
  50.             log(sm.getString("webappLoader.reloading"));   
  51.             try {   
  52.                 threadStart();   
  53.             } catch (IllegalStateException e) {   
  54.                 throw new LifecycleException(e);   
  55.             }   
  56.         }   
  57.     }   
  58. ......   
  59. private WebappClassLoader createClassLoader()   
  60.         throws Exception {   
  61.         Class clazz = Class.forName(loaderClass);   
  62.         WebappClassLoader classLoader = null;   
  63.         if (parentClassLoader == null) {   
  64.             // Will cause a ClassCast is the class does not extend WCL, but   
  65.             // this is on purpose (the exception will be caught and rethrown)   
  66.             classLoader = (WebappClassLoader) clazz.newInstance();   
  67.         } else {   
  68.             Class[] argTypes = { ClassLoader.class };   
  69.             Object[] args = { parentClassLoader };   
  70.             Constructor constr = clazz.getConstructor(argTypes);   
  71.             classLoader = (WebappClassLoader) constr.newInstance(args);   
  72.         }   
  73.         return classLoader;   
  74.     }  

 

在WebappClassLoader中,其findClass的搜索顺序与一般的ClassLoader的搜索顺序不同。

一般的ClassLoader的搜索顺序为:

将其委托给父ClassLoader,如果父ClassLoader不能载入相应类,则才交给自己处理

但是WebappClassLoader中,其是先由自己来处理,如果不行再委托给父ClassLoader

相关源代码如下:

 

  1. Class clazz = null;   
  2.        try {   
  3.            if (debug >= 4)   
  4.                log("      findClassInternal(" + name + ")");   
  5.            try {   
  6.                clazz = findClassInternal(name);   
  7.            } catch(ClassNotFoundException cnfe) {   
  8.                if (!hasExternalRepositories) {   
  9.                    throw cnfe;   
  10.                }   
  11.            } catch(AccessControlException ace) {   
  12.                ace.printStackTrace();   
  13.                throw new ClassNotFoundException(name);   
  14.            } catch (RuntimeException e) {   
  15.                if (debug >= 4)   
  16.                    log("      -->RuntimeException Rethrown", e);   
  17.                throw e;   
  18.            }   
  19.            if ((clazz == null) && hasExternalRepositories) {   
  20.                try {   
  21.                    clazz = super.findClass(name);   
  22.                } catch(AccessControlException ace) {   
  23.                    throw new ClassNotFoundException(name);   
  24.                } catch (RuntimeException e) {   
  25.                    if (debug >= 4)   
  26.                        log("      -->RuntimeException Rethrown", e);   
  27.                    throw e;   
  28.                }   
  29.            }   
  30.            if (clazz == null) {   
  31.                if (debug >= 3)   
  32.                    log("    --> Returning ClassNotFoundException");   
  33.                throw new ClassNotFoundException(name);   
  34.            }   
  35.        } catch (ClassNotFoundException e) {   
  36.            if (debug >= 3)   
  37.                log("    --> Passing on ClassNotFoundException", e);   
  38.            throw e;   
  39.        }  

 

以下引自tomcat的说明文档,说明了加载类的顺序

Therefore, from the perspective of a web application, class or resource loading looks in the following repositories, in this order:

  • /WEB-INF/classes of your web application
  • /WEB-INF/lib/*.jar of your web application
  • Bootstrap classes of your JVM
  • System class loader classses (described above)
  • $CATALINA_HOME/common/classes
  • $CATALINA_HOME/common/endorsed/*.jar
  • $CATALINA_HOME/common/lib/*.jar
  • $CATALINA_BASE/shared/classes
  • $CATALINA_BASE/shared/lib/*.jar
分享到:
评论

相关推荐

    Tomcat研究之ClassLoader.pdf

    ### Tomcat中的ClassLoader详解 #### 一、引言 在深入了解Tomcat的工作原理时,一个重要的组成部分就是其ClassLoader机制。本文旨在深入剖析Tomcat中特有的类加载器(ClassLoader)体系结构,帮助读者理解Tomcat...

    Tomcat 5.0.18 ClassLoader source code insight

    总的来说,深入研究Tomcat 5.0.18的ClassLoader源码,不仅可以提升我们的技术水平,还能让我们更好地应对Java Web开发中的挑战。对于那些想要深入理解Java类加载机制和Tomcat内部工作的开发者,这是一个不可多得的...

    tomcat 类加载机制 —— ClassLoader

    《Tomcat类加载机制——ClassLoader详解》 在Java Web开发中,Tomcat作为最常用的Servlet容器,其类加载机制对于...通过阅读和研究Tomcat源码,我们可以更深入地了解这一机制,从而更好地驾驭这个强大的Web服务器。

    Tomcat源代码学习研究

    - **Classloading**:Tomcat使用定制的ClassLoader加载Web应用的类,遵循“父类加载优先”原则。 6. **连接器与协议处理** - **NIO和Apr**:Tomcat提供了多种连接器实现,如基于Java NIO的 Coyote Connector 和...

    Tomcat:apache-tomcat-6.0.18

    5. **ClassLoader机制**:Tomcat使用自定义的ClassLoader来加载Web应用程序的类,确保不同应用之间的类隔离,防止冲突。 Tomcat 6.0.18版的特性包括: 1. **性能优化**:相对于之前的版本,6.0.18进行了性能调优,...

    tomcat类加载器

    4. Common ClassLoader:在Tomcat中,它是所有Web应用共享的类加载器,用于加载`common.loader`配置项指定的类路径。 5. WebApp ClassLoader:每个Web应用有自己的类加载器,它加载应用的`WEB-INF/classes`和`WEB-...

    tomcat 学习与分析总结资料

    通过研究这个脚本,我们可以了解如何配置JVM参数,如内存分配、堆大小以及设置系统属性,以优化Tomcat的性能。 2. **Tomcat工作原理** Tomcat基于Coyote和Apr(Apache Portable Runtime)处理HTTP请求。Coyote是...

    深入剖析Tomcat 随书 源码

    《深入剖析Tomcat》这本书是Java开发者们探索Tomcat服务器内部机制的重要参考资料,它带领读者逐步揭开Tomcat的...通过学习和研究Tomcat源码,我们可以提升技术水平,解决实际问题,甚至为Tomcat社区贡献自己的力量。

    Tomcat6的源码

    5. **ClassLoader机制**:Tomcat的类加载机制允许每个Web应用拥有自己的类加载器,避免类冲突。理解这部分源码对于理解和解决部署问题至关重要。 6. **Session管理**:Tomcat处理用户会话,包括创建、跟踪和管理...

    java类加载器-tomcat中的类加载器

    4. 最后,如果所有父类加载器都未能加载,Catalina ClassLoader才加载Tomcat自身的类。 VSD文件可能包含一个流程图,详细描绘了Tomcat类加载器的工作流程和关系,这对于理解类加载机制非常有帮助。通过阅读和分析该...

    apache-tomcat-7.0.81-src 源码免费下载

    10. **网络编程**:Tomcat底层使用NIO(非阻塞I/O)和BIO(阻塞I/O)模型,这在`java/org/apache/tomcat/util/net`目录下可以深入研究。 通过学习和分析这些源码,开发者不仅可以提升对Java Web技术的理解,还可以...

    apache-tomcat-7.0.40-src

    通过研究"apache-tomcat-7.0.40-src",开发者可以更好地理解Web服务器的工作流程,定制化自己的Tomcat实例,优化性能,或者为社区贡献代码。对于Java Web开发人员来说,深入学习和理解Tomcat源码是提升技能的重要...

    tomcat8源码的maven项目

    3. **学习部署和加载机制**:Tomcat如何加载和管理Web应用程序,包括WAR文件的部署和Classloader的工作原理。 4. **研究线程模型**:Tomcat如何使用线程来处理并发请求,以及线程池的配置和管理。 5. **深入JSP和...

    tomcat-4.1.40-src

    3. **启动流程**:Tomcat的启动过程始于`bin/catalina.sh`或`catalina.bat`,这些脚本会初始化Java环境,并加载`catalina.jar`中的`org.apache.catalina.startup.ClassLoader`,接着加载`Server`对象,初始化`...

    tomcat 6 源码

    5. **ClassLoader**:Tomcat使用自定义的ClassLoader来加载Web应用的类。这使得不同应用之间能隔离地运行,避免类冲突。 6. **Lifecycle**:所有Tomcat组件都遵循生命周期接口,如`org.apache.catalina.Lifecycle`...

    apache-tomcat-源码-lib包

    源码中,ClassLoader的实现(例如`org.apache.catalina.loader.WebappClassLoaderBase`)值得深入研究。 5. **部署和配置**:Tomcat支持多种方式部署Web应用,如WAR文件、目录结构或者通过管理接口。源码中,你可以...

    Tomcat7 源码Eclipse工程

    总的来说,通过研究Tomcat7的源码Eclipse工程,不仅可以提升Java Web开发的专业技能,还能深入了解服务器架构设计,这对于优化应用性能、排查故障以及定制化开发具有极大的价值。在实践中,我们可以结合官方文档和...

    tomcat_src

    通过对"Tomcat_src"的深入研究,开发者可以提升自己的技术水平,更好地驾驭这个强大的Web服务器。无论是为了学习、调试还是定制,Tomcat源代码都是一份宝贵的资源,值得每一个Java Web开发者珍视。

Global site tag (gtag.js) - Google Analytics