Tomcat 架构分析(二) ClassLoader详解

来源:互联网 发布:金蝶软件服务商 编辑:程序博客网 时间:2024/04/28 12:19
Tomcat 架构分析(二) ClassLoader详解



前言:
    上一节提到,Tomcat的五个子模块:Jsper模块Servlet和Jsp模块Catalina模块Connector模块Resource模块,本节是对lib包下的详细讲解,以及Tomcat是如何加载类(ClassLoader

1.简介

   与许多服务器应用程序一样,Tomcat安装了各种类装入器(也就是实现java.lang.classloader的类),以允许容器的不同部分和在容器上运行的web应用程序访问不同的可用类和资源的存储库。该机制用于提供Servlet规范中定义的功能。
    在Java环境中,类装入器被安排在父-子树中。通常,当一个类装入器被要求装入一个特定的类或资源时,它首先将请求委托给父类装入器,然后只在父类装入器(s)不能找到所请求的类或资源时才查找它自己的存储库。请注意,web应用程序类加载器的模型与下面略有不同,但主要原则是相同的。
    在启动Tomcat时,它会创建一组类装入器,这些装入器会被组织到下面的父-子关系中,其中父类装入器位于子类装入器之上:

        


2.类加载的定义

如上图所示,Tomcat在初始化时创建了以下类加载器:

1.Bootstrap —— 这个类装入器包含Java虚拟机提供的基本运行时类,以及从系统扩展目录(javahome/jre/lib/ext)中提供的JAR文件的任何类。注意:有些jvm可能会将它作为一个以上的类装入器来实现,或者它可能不可见(作为一个类装入器)。

2.System —— 这个类装入器通常从CLASSPATH环境变量的内容中初始化。对于Tomcat内部类和web应用程序,所有这些类都是可见的。
然而,标准的Tomcat启动脚本($catalinahome/bin/catalina.sh或%catalinhome%bin catalina.bat)完全忽略CLASSPATH环境变量本身的内容,而是从以下存储库构建系统类装入器:

  • $CATALINA_HOME/bin/bootstrap.jar— 包含用于初始化Tomcat服务器的main()方法,以及它所依赖的类装入器实现类。

  • $CATALINA_BASE/bin/tomcat-juli.jaror$CATALINA_HOME/bin/tomcat-juli.jar — 日志实现类。这些包括对java.util的增强类。被称为Tomcat JULI的日志API,以及由Tomcat内部使用的Apache Commons日志库的一个包重命名的副本。

            如果tomcat-juli.jar是在$CATALINA_BASE/bin 中使用的,它是用在 $CATALINA_HOME/bin 中使用的。它在某些日志配置中很有用

  • $CATALINA_HOME/bin/commons-daemon.jar— 来自Apache Commons守护进程项目的类。这个JAR文件不在由catalina.bat|.sh 构建的类路径中,但是是从bootstrap.jar的文件中引用的。


3.Common ——这个类装入器包含了对Tomcat内部类和所有web应用程序都可见的其他类。

通常,应用程序类不应该放在这里。这个类装入器的位置是由 common.loader perporties 定义 在 $CATALINA_BASE/conf/catalina.properties。
默认设置将按照以下顺序搜索以下位置:

* 未打包的 classes and resources in $CATALINA_BASE/lib
* JAR files in $CATALINA_BASE/lib
* 未打包的 classes and resources in $CATALINA_HOME/lib
* JAR files in $CATALINA_HOME/lib

如图,为windows解压后lib文件下(*.jar包)分布情况:

        

默认的,包括以下文件:

  • annotations-api.jar— JavaEE注解类
  • catalina.jar— 实现Tomcat Catalina Servlet容器的一部分
  • catalina-ant.jar— Tomcat Catalina 编译任务.
  • catalina-ha.jar— 高可用性的包.
  • catalina-storeconfig.jar— 当前版本的一些配置文件
  • catalina-tribes.jar— 支持通讯的文件.
  • ecj-*.jar— Java编译器Eclipse提供的API.
  • el-api.jar— EL表达式 3.0 API.
  • jasper.jar— Tomcat解析JSP的编译和运行.
  • jasper-el.jar— Tomcat解析EL表达式的实现。
  • jsp-api.jar— JSP 2.3 API.
  • servlet-api.jar— Servlet 3.1 API.
  • tomcat-api.jar— Tomcat定义的一些服务.
  • tomcat-coyote.jar— Tomcat connectors(连接器) and 通用的classes.
  • tomcat-dbcp.jar— Database connection pool(数据库连接池) implementation based on package-renamed copy of Apache Commons Pool and Apache Commons DBCP.
  • tomcat-i18n-**.jar— Optional JARs containing resource bundles for other languages. As default bundles are also included in each individual JAR, they can be safely removed if no internationalization of messages is needed.
  • tomcat-jdbc.jar— An alternative database connection pool implementation, known as Tomcat JDBC pool. Seedocumentationfor more details.
  • tomcat-util.jar— Common classes used by various components of Apache Tomcat.
  • tomcat-websocket.jar— WebSocket 1.1 implementation
  • websocket-api.jar— WebSocket 1.1 API



4.WebappX ——为每个web应用程序创建一个类装入器,该应用程序部署在一个Tomcat实例中。在web应用程序的/web/web/类目录中所有未打包的类和资源,以及web应用程序/web应用程序/lib目录下的JAR文件中的类和资源,都可以在这个web应用程序中看到,而不是其他的。

正如上面所提到的,web应用程序类加载器与默认的Java委托模型(按照Servlet规范中的建议,web应用程序类加载器的建议)不同。当请求从web应用程序的WebappX类加载器加载一个类时,这个类装入器将首先在本地存储库中查找,而不是在查找之前进行委托。也有例外。属于JRE基类的类不能被覆盖。有一些例外,比如XML解析器组件,可以使用适当的JVM特性覆盖,这是Java小于=8所支持的标准覆盖特性,以及用于Java 9+的可升级模块特性。最后,web应用程序类加载器将总是为JavaEE API类的第一个代理,为Tomcat(Servlet、JSP、EL、WebSocket)所实现的规范。Tomcat中的所有其他类装入器都遵循通常的代理模式。
因此,从web应用程序的角度来看,类或资源加载在以下存储库中如下所显示的:
  • Bootstrap classes of your JVM
  • /WEB-INF/classesof your web application
  • /WEB-INF/lib/*.jarof your web application
  • System class loader classes (described above)
  • Common class loader classes (described above)
如果Web应用程序配置了 "<Loader delegate="true"/>", 则ClassLoader的加载顺序为:
  • Bootstrap classes of your JVM
  • System class loader classes (described above)
  • Common class loader classes (described above)
  • /WEB-INF/classesof your web application
  • /WEB-INF/lib/*.jarof your web application


3.XML的分析与Java的关系

从Java 1.4开始,一个JAXP api的副本和一个XML解析器被打包在JRE中。这对希望使用自己的XML解析器的应用程序产生了影响。

在旧版本的Tomcat中,您可以简单地替换Tomcat库目录中的XML解析器来更改所有web应用程序使用的解析器。然而,当您正在运行Java的现代版本时,这种技术将不会有效,因为通常的类装入器委托过程将始终选择JDK中的实现,而不是这个。

Java8或以下支持一种称为“支持的标准覆盖机制”的机制,允许替换在JCP之外创建的api(即来自W3C的DOM和SAX)。它还可以用于更新XML解析器实现。有关更多信息,请参见:http://docs.oracle.com/javase/1.5.0/docs/guide/standards/index.html对于Java 9+,使用可升级的模块特性。

Tomcat利用了支持的机制,包括系统属性设置——djava.base。在启动容器的命令行中,dirs=$javaendorseddirs。这个选项的默认值是$catalinahome/base。这个支持的目录不是默认创建的。请注意,已支持的特性不再支持Java 9,而上面的系统属性只有在$catalinahome/base存在时才会设置,或者已经设置了可变的javaendorseddirs。

注意,覆盖任何JRE组件都有风险。如果覆盖的组件不提供100%兼容的API(例如Xerces提供的API与JRE提供的XML API不兼容),那么Tomcat和/或部署的应用程序将会出现错误的风险。


4.在安全模式下运行

当在安全管理器下运行时,允许加载类的位置也将取决于您的策略文件的内容。由于内容较长,将在后续的文章介绍。



About Me:

  • Github地址:https://github.com/noseparte 
  • Email: noseparte@aliyun.com     有java与hadoop相关的技术问题,可以发私信与我交流。
  • NPM地址: https://www.npmjs.com/~noseparte
  • WebSite: http://www.noseparte.com/  Copyright © 2017 noseparte







原创粉丝点击