`
endual
  • 浏览: 3520336 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Tomcat 启动时类加载顺序

    博客分类:
  • java
 
阅读更多

Tomcat 启动时类加载顺序

Tomcat启动时classloader加载顺序 
  Tomcat的class加载的优先顺序一览   
  1.最先是$JAVA_HOME/jre/lib/ext/下的jar文件。   
  2.环境变量CLASSPATH中的jar和class文件。   
  3.$CATALINA_HOME/common/classes下的class文件。   
  4.$CATALINA_HOME/commons/endorsed下的jar文件。   
  5.$CATALINA_HOME/commons/i18n下的jar文件。   
  6.$CATALINA_HOME/common/lib   下的jar文件。   
  (JDBC驱动之类的jar文件可以放在这里,这样就可以避免在server.xml配置好数据源却出现找不到JDBC   Driver的情况。)   
  7.$CATALINA_HOME/server/classes下的class文件。   
  8.$CATALINA_HOME/server/lib/下的jar文件。   
  9.$CATALINA_BASE/shared/classes   下的class文件。   
  10.$CATALINA_BASE/shared/lib下的jar文件。   
  11.各自具体的webapp   /WEB-INF/classes下的class文件。   
  12.各自具体的webapp   /WEB-INF/lib下的jar文件。   
  class的搜寻顺序如下:   
  -------------   
  Bootstrap   classes   of   your   JVM     
  System   class   loader   classses   (described   above)     
  /WEB-INF/classes   of   your   web   application     
  /WEB-INF/lib/*.jar   of   your   web   application     
  $CATALINA_HOME/common/classes     
  $CATALINA_HOME/common/endorsed/*.jar     
  $CATALINA_HOME/common/i18n/*.jar     
  $CATALINA_HOME/common/lib/*.jar     
  $CATALINA_BASE/shared/classes     
  $CATALINA_BASE/shared/lib/*.jar     
  --------------   
  因此放在不同webapp里的class文件,会被classloader加载成不同的实例。   
  例如假设下面两个不同内容的class。分别放在不同的webapp的class目录下。   
  package   com.lizongbo;   
  public   class   TestClass   {   
      private   String   NAME="lizongbo";   
  }   
  package   com.lizongbo;   
  public   class   TestClass   {   
      private   String   NAME="li_zongbo";   
  }   
  在不同的webapp得到的com.lizongbo.NAME结果是不同的,且互不影响。   
  但是注意,以下包名开头的class例外:   
  javax.*     
  org.xml.sax.*     
  org.w3c.dom.*     
  org.apache.xerces.*     
  org.apache.xalan.*     
  ps,注意.在各个jar中的/META-INF/MAINFEST.MF文件里Class-Path键值对,也会提供jar的加载优先顺序。   
  例如某jar的MAINFEST.MF内容如下:   
  Manifest-Version:   1.0   
  Created-By:   lizongbo   
  Class-Path:   commons-beanutils.jar   
  Class-Path:   commons-collections.jar   
  Class-Path:   commons-dbcp.jar   
  Class-Path:   commons-digester.jar   
  Class-Path:   commons-logging.jar   
  Class-Path:   commons-pool.jar   
  Class-Path:   commons-services.jar   
  Class-Path:   commons-validator.jar   
  Class-Path:   jakarta-oro.jar   
  Main-Class:   com.lizongbo.MyTestClass   
  那么在加载这个jar的时候,会先在此jar所在目录下依次先加载commons-beanutils.jar,commons-collections.jar。。。等jar文件。   
  在不同的地方放置jar和class可能会产生意想不到的后果,,尤其是不同版本的jar文件,因此在实际应用部署web应用时候要特别留心.   
  例如   使用javamail常见的一个出错信息:   
  javax.mail.NoSuchProviderException:   No   provider   for   smtp   
  其真实原因就很可能如下:   
  在不同的加载jar的目录下放置了不同版本的mail.jar,比如一个是javamail1.3.1的mail.jar   
  在D:/jakarta-tomcat-5.5.8/common/lib下,而另外一个是javamail1.3.2的mail.jar在   
  D:/jakarta-tomcat-5.5.8/webapps/lizongbo/WEB-INF/lib下,   
  那么lizongbo这个webapp中使用到javamail进行邮件发送的时候,便会出现No   provider   for   smtp的错误。   
******************************************************************* 
ClassLoader in Tomcat 
************************************ 
1 - Tomcat 的类载入器的结构 


Tomcat Server 在启动的时候将构造一个ClassLoader树,以保证模块的类库是私有的 
Tomcat Server的ClassLoader结构如下: 


        +-----------------------------+  

        |         Bootstrap           |  

        |             |               |  

        |          System             |  

        |             |               |  

        |          Common             |  

        |         /      /            |  

        |     Catalina  Shared        |  

        |               /    /        |  

         |          WebApp1  WebApp2   |  

        +-----------------------------+ 


其中: 
- Bootstrap - 载入JVM自带的类和$JAVA_HOME/jre/lib/ext/*.jar 
- System - 载入$CLASSPATH/*.class 
- Common - 载入$CATALINA_HOME/common/...,它们对TOMCAT和所有的WEB APP都可见 
- Catalina - 载入$CATALINA_HOME/server/...,它们仅对TOMCAT可见,对所有的WEB APP都不可见 
- Shared - 载入$CATALINA_HOME/shared/...,它们仅对所有WEB APP可见,对TOMCAT不可见(也不必见) 
- WebApp - 载入ContextBase?/WEB-INF/...,它们仅对该WEB APP可见 



2 - ClassLoader 的工作原理 


每个运行中的线程都有一个成员contextClassLoader,用来在运行时动态地载入其它类 
系统默认的contextClassLoader是systemClassLoader,所以一般而言java程序在执行时可以使用JVM自带的类、$JAVA_HOME/jre/lib/ext/中的类和$CLASSPATH/中的类 
可以使用 Thread.currentThread().setContextClassLoader(...); 更改当前线程的contextClassLoader,来改变其载入类的行为 


ClassLoader 被组织成树形,一般的工作原理是: 
1) 线程需要用到某个类,于是contextClassLoader被请求来载入该类 
2) contextClassLoader请求它的父ClassLoader来完成该载入请求 
3) 如果父ClassLoader无法载入类,则contextClassLoader试图自己来载入 


注意 :WebApp?ClassLoader的工作原理和上述有少许不同: 
它先试图自己载入类(在ContextBase?/WEB-INF/...中载入类),如果无法载入,再请求父ClassLoader完成 


由此可得: 
- 对于WEB APP线程,它的contextClassLoader是WebApp?ClassLoader 
- 对于Tomcat Server线程,它的contextClassLoader是CatalinaClassLoader 



3 类的查找 

ClassLoader类中loadClass方法为缺省实现,用下面的顺序查找类: 

1、调用findLoadedClass方法来检查是否已经被加载。如果没有则继续下面的步骤。 

2、如果当前类装载器有一个指定的委托父装载器,则用委托父装载器的loadClass方法加载类,也就是委托给父装载器加载相应的类。 

3、如果这个类装载器的委托层级体系没有一个类装载器加载该类,则使用类装载器定位类的特定实现机制,调用findClass方法来查找类。 



4 - 部分原代码分析 


4.1 - org/apache/catalina/startup/Bootstrap.java 

Bootstrap中定义了三个classloader:commonLoader,catalinaLoader,sharedLoader.三者关系如下: 


// 注意三个自己定置的ClassLoader的层次关系:  

            // systemClassLoader (root)  

              //   +--- commonLoader  

            //          +--- catalinaLoader  

            //          +--- sharedLoader 


Tomcat Server 线程的起点 
构造ClassLoader树,通过Thread.currentThread().setContextClassLoader(catalinaLoader)设置当前的classloader为catalinaLoader。 
载入若干类,然后转入org.apache.catalina.startup.Catalina类中 



4.2 org.apache.catalina.loader.StandardClassLoader.java 

通过看loadClass这个方法来看tomcat是如何加载类的,顺序如下: 

(0) Check our previously loaded class cache查找已经装载的class 
        clazz = findLoadedClass(name); 

(1) If a system class, use system class loader通过系统classloader来装载class 

        ClassLoader loader = system; 
            clazz = loader.loadClass(name); 

(2) Delegate to our parent if requested如果有代理则使用父类classloader 

            ClassLoader loader = parent; 
            if (loader == null) 
                loader = system; 
            clazz = loader.loadClass(name); 

(3) Search local repositories 查找本地类池,比如$CATALINA_HOME/server 

           clazz = findClass(name); 

(4) Delegate to parent unconditionally 默认使用代理装载器 



[ 查看代码] 


4.3 - org/apache/catalina/startup/ClassLoaderFactory.java 


根据设置创建并返回StandardClassLoader的实例 


[ 查看代码] 


4.4 - org/apache/catalina/loader/StandardClassLoader.java 


类载入器 


4.5 - org/apache/catalina/startup/SecurityClassLoad.java 


该类仅包含一个静态方法,用来为catalinaLoader载入一些类 


[ 查看代码] 


Appendix - 参考 


[1] http://jakarta.apache.org/tomcat/ 中的Tomcat 4.1.x文档Class Loader HOW-TO 


在一个 JVM 中可能存在多个 ClassLoader ,每个 ClassLoader 拥有自己的 NameSpace 。一个 ClassLoader 只能拥有一个 class 对象类型的实例,但是不同的 ClassLoader 可能拥有相同的 class 对象实例,这时可能产生致命的问题。如 ClassLoaderA ,装载了类 A 的类型实例 A1 ,而 ClassLoaderB ,也装载了类 A 的对象实例 A2 。逻辑上讲 A1=A2 ,但是由于 A1 和 A2 来自于不同的 ClassLoader ,它们实际上是完全不同的,如果 A 中定义了一个静态变量 c ,则 c 在不同的 ClassLoader 中的值是不同的。
分享到:
评论

相关推荐

    Tomcat启动时类加载顺序

    详细说明了tomcat启动过程中 加载资源的顺序

    tomcat详解与启动加载顺序

    tomcat详解与启动加载顺序 tomcat详解与启动加载顺序

    Tomcat启动顺序

    Bootstrap-->System -->Common-->Catalina/Shared-->WebApp

    Tomcat中用web.xml控制Web应用详解

    Tomcat 中 web.xml 文件是 Web 应用的核心配置文件,负责管理 Web 应用的生命周期、Servlet 的加载顺序、Filter 的配置等。下面对 web.xml 文件中的重要元素进行详细解释。 context-param 元素 context-param 元素...

    TOMACT配置详解

    TOMCAT的类加载顺序如下: 1. $JAVA_HOME/jre/lib/ext/下的Jar文件。 2. 环境变量CLASSPATH中的Jar和class文件。 3. $CATALINA_HOME/common/classes下的class文件。 4. $CATALINA_HOME/commons/endorsed下的Jar文件...

    14-Servlet注解以及IDEA与tomcat相关配置.pdf

    * loadOnStartup 属性:指定 Servlet 的加载顺序,默认为 -1。 * initParams 属性:指定 Servlet 的初始化参数,默认为空数组。 * asyncSupported 属性:指定 Servlet 是否支持异步处理,默认为 false。 * smallIcon...

    解决The project cannot be built until build path

    其中,Libraries 是指项目所依赖的 jar 包或其他库文件,而 Order and Export 则是指项目的类加载顺序和输出设置。 解决方法 解决“项目无法构建直到build path”问题的方法可以按照以下步骤进行: 1. 检查 Build...

    java 面试题 总结

    以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 public class ThreadTest1{ private int j; public static void main(String args[]){ ThreadTest1 tt=new ThreadTest1(); Inc inc=tt.new Inc(); ...

    java初学者必看

    11.2.2 线程的创建和启动 11.2.3 线程状态转换 11.2.4 等待线程结束 11.3 线程调度 11.4 线程同步 11.4.1 同步概念 11.4.2 同步格式 11.4.3 同步应用 11.5 线程通信 11.5.1 生产者/消费者 11.5.2 共享队列...

    超级有影响力霸气的Java面试题大全文档

    引用类型和原始类型具有不同的特征和用法,它们包括:大小和速度问题,这种类型以哪种类型的数据结构存储,当引用类型和原始类型用作某个类的实例数据时所指定的缺省值。对象引用实例变量的缺省值为 null,而原始...

    Java开发技术大全 电子版

    9.6利用反射获取运行时类信息293 9.6.1使用isInstance()方法判断所属类294 9.6.2获取成员方法信息295 9.6.3获取构造方法信息296 9.6.4获取类的成员属性297 9.6.5根据方法的名称来执行方法299 9.6.6创建新的...

    java面试题

    以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 107 84.4. 现在输入n个数字,以逗号”,”分开;然后可选择升或者降序排序;按提交键就在另一页面显示按什么排序,结果为,提供reset 108 84.5. 金额...

    SpringBoot开发非常美观的java博客系统(包含后台管理功能)

    三、idea以maven项目导入该项目后,发现没有maven的依赖包时,需要对每个maven module进行clear和install,并且注意maven的依赖顺序 SpringBoot开发非常美观的java博客系统(包含后台管理功能) SpringBoot开发非常...

    Java面试宝典2010版

    1、一个".java"源文件中是否可以包括多个类(不是内部类)?有什么限制? 2、Java有没有goto? 3、说说&和&&的区别。 4、在JAVA中如何跳出当前的多重嵌套循环? 5、switch语句能否作用在byte上,能否作用在long上...

    java基础题 很全面

    以下程序使用内部类实现线程,对j增减的时候没有考虑顺序问题。 31 6. 写一段Jdbc连Oracle的程序. 32 7. 编码实现内部类 34 8. 输入n个数字,以逗号,分开;然后可选择升或者降序排序;按提交键就在另一页面显示按...

    Spring.3.x企业应用开发实战(完整版).part2

    4.11.2 使用基于Java类的配置信息启动Spring容器 4.12 不同配置方式比较 4.13 小结 第5章 Spring容器高级主题 5.1 Spring容器技术内幕 5.1.1 内部工作机制 5.1.2 BeanDefinition 5.1.3 InstantiationStrategy 5.1.4 ...

    Spring3.x企业应用开发实战(完整版) part1

    4.11.2 使用基于Java类的配置信息启动Spring容器 4.12 不同配置方式比较 4.13 小结 第5章 Spring容器高级主题 5.1 Spring容器技术内幕 5.1.1 内部工作机制 5.1.2 BeanDefinition 5.1.3 InstantiationStrategy 5.1.4 ...

    单点登录源码

    Spring+SpringMVC+Mybatis框架集成公共模块,包括公共配置、MybatisGenerator扩展插件、通用BaseService、工具类等。 > zheng-admin 基于bootstrap实现的响应式Material Design风格的通用后台管理系统,`zheng`...

Global site tag (gtag.js) - Google Analytics