为了账号安全,请及时绑定邮箱和手机立即绑定

Tomcat 架构分析(二) ClassLoader详解

标签:
Java
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.jar or $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. See documentation for 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/classes of your web application

/WEB-INF/lib/*.jar of 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/classes of your web application

/WEB-INF/lib/*.jar of 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.背书。在启动容器的命令行中,dirs=$javaendorseddirs。这个选项的默认值是$catalinahome/背书。这个支持的目录不是默认创建的。请注意,已支持的特性不再支持Java 9,而上面的系统属性只有在$catalinahome/背书存在时才会设置,或者已经设置了可变的javaendorseddirs。

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

4.在安全模式下运行

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

点击查看更多内容
8人点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
JAVA开发工程师
手记
粉丝
7115
获赞与收藏
545

关注作者,订阅最新文章

阅读免费教程

感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消