类加载器操作指南
目录
概述
与许多服务器应用程序一样,Tomcat 安装了各种类加载器(即实现 java.lang.ClassLoader
的类),以允许容器的不同部分以及在容器上运行的 Web 应用程序访问不同的可用类和资源存储库。此机制用于提供 Servlet 规范(版本 2.4)中定义的功能,特别是第 9.4 节和第 9.6 节。
在 Java 环境中,类加载器以父子树的形式排列。通常,当类加载器被要求加载特定类或资源时,它会首先将请求委托给父类加载器,然后仅当父类加载器无法找到请求的类或资源时,才会在其自己的存储库中查找。请注意,如以下所述,Web 应用程序类加载器的模型略有不同,但主要原理相同。
当 Tomcat 启动时,它会创建一组类加载器,这些类加载器以以下父子关系组织,其中父类加载器位于子类加载器之上
Bootstrap
|
System
|
Common
/ \
Webapp1 Webapp2 ...
以下部分详细讨论了每个类加载器的特性,包括它们使可见的类和资源的来源。
类加载器定义
如上图所示,Tomcat 在初始化时会创建以下类加载器。
Bootstrap — 此类加载器包含 Java 虚拟机提供的基本运行时类,以及系统扩展目录(
$JAVA_HOME/jre/lib/ext
)中存在的 JAR 文件中的任何类。注意:一些 JVM 可能会将此实现为多个类加载器,或者它可能根本不可见(作为类加载器)。System — 此类加载器通常从
CLASSPATH
环境变量的内容初始化。所有此类类对 Tomcat 内部类和 Web 应用程序都可见。但是,标准 Tomcat 启动脚本($CATALINA_HOME/bin/catalina.sh
或%CATALINA_HOME%\bin\catalina.bat
)完全忽略CLASSPATH
环境变量本身的内容,而是从以下存储库构建 System 类加载器。$CATALINA_HOME/bin/bootstrap.jar — 包含用于初始化 Tomcat 服务器的 main() 方法,以及它所依赖的类加载器实现类。
$CATALINA_BASE/bin/tomcat-juli.jar 或 $CATALINA_HOME/bin/tomcat-juli.jar — 日志实现类。这些包括对
java.util.logging
API 的增强类,称为 Tomcat JULI,以及 Tomcat 内部使用的 Apache Commons Logging 库的包重命名副本。有关更多详细信息,请参见 日志记录文档。如果 $CATALINA_BASE/bin 中存在
tomcat-juli.jar
,则使用它而不是 $CATALINA_HOME/bin 中的tomcat-juli.jar
。它在某些日志记录配置中很有用。$CATALINA_HOME/bin/commons-daemon.jar — 来自 Apache Commons Daemon 项目的类。此 JAR 文件不在
catalina.bat
|.sh
脚本构建的CLASSPATH
中,但从 bootstrap.jar 的清单文件中引用。
Common — 此类加载器包含其他对 Tomcat 内部类和所有 Web 应用程序都可见的类。
通常,应用程序类不应放置在此处。此类加载器搜索的位置由
$CATALINA_BASE/conf/catalina.properties
中的common.loader
属性定义。默认设置将按列出的顺序搜索以下位置。$CATALINA_BASE/lib
中的解压缩类和资源。$CATALINA_BASE/lib
中的 JAR 文件。$CATALINA_HOME/lib
中的解压缩类和资源。$CATALINA_HOME/lib
中的 JAR 文件。
默认情况下,这包括以下内容。
- annotations-api.jar — Jakarta Annotations 2.1.1 类。
- catalina.jar — Tomcat 的 Catalina servlet 容器部分的实现。
- catalina-ant.jar — 可选。用于处理 Manager Web 应用程序的 Tomcat Catalina Ant 任务。
- catalina-ha.jar — 可选。基于 Tribes 构建的提供会话集群功能的高可用性包。
- catalina-ssi.jar — 可选。服务器端包含模块。
- catalina-storeconfig.jar — 可选。从当前状态生成 XML 配置文件。
- catalina-tribes.jar — 可选。高可用性包使用的组通信包。
- ecj-*.jar — 可选。用于将 JSP 编译为 Servlet 的 Eclipse JDT Java 编译器。
- el-api.jar — 可选。EL 5.0 API。
- jakartaee-migration-*-shaded.jar — 可选。提供将 Web 应用程序从 Java EE 8 转换为 Jakarta EE 9 的功能。
- jasper.jar — 可选。Tomcat Jasper JSP 编译器和运行时。
- jasper-el.jar — 可选。Tomcat EL 实现。
- jaspic-api.jar — Jakarta Authentication 3.0 API。
- jsp-api.jar — 可选。Jakarta Pages 3.1 API。
- servlet-api.jar — Jakarta Servlet 6.0 API。
- tomcat-api.jar — Tomcat 定义的几个接口。
- tomcat-coyote.jar — Tomcat 连接器和实用程序类。
- tomcat-dbcp.jar — 可选。基于重命名包的 Apache Commons Pool 2 和 Apache Commons DBCP 2 的数据库连接池实现。
- tomcat-i18n-**.jar — 可选的 JAR 包含其他语言的资源包。由于默认包也包含在每个单独的 JAR 中,因此如果不需要消息国际化,可以安全地删除它们。
- tomcat-jdbc.jar — 可选。另一种数据库连接池实现,称为 Tomcat JDBC 池。有关更多详细信息,请参阅 文档。
- tomcat-jni.jar — 提供与 Tomcat Native 库的集成。
- tomcat-util.jar — Apache Tomcat 各个组件使用的通用类。
- tomcat-util-scan.jar — 提供 Tomcat 使用的类扫描功能。
- tomcat-websocket.jar — 可选。Jakarta WebSocket 2.1 实现
- websocket-api.jar — 可选。Jakarta WebSocket 2.1 API
- websocket-client-api.jar — 可选。Jakarta WebSocket 2.1 客户端 API
WebappX — 为在单个 Tomcat 实例中部署的每个 Web 应用程序创建一个类加载器。Web 应用程序的
/WEB-INF/classes
目录中的所有解压缩类和资源,以及 Web 应用程序的/WEB-INF/lib
目录下的 JAR 文件中的类和资源,对该 Web 应用程序可见,但对其他 Web 应用程序不可见。
如上所述,Web 应用程序类加载器偏离了默认的 Java 委托模型(符合 Servlet 规范版本 2.4,第 9.7.2 节 Web 应用程序类加载器中的建议)。当处理从 Web 应用程序的 WebappX 类加载器加载类的请求时,此类加载器将首先查看本地存储库,而不是在查看之前进行委托。有一些例外。属于 JRE 基本类的类不能被覆盖。有一些例外,例如可以使用可升级模块功能覆盖的 XML 解析器组件。最后,Web 应用程序类加载器将始终首先委托 Jakarta EE API 类,以获取 Tomcat 实现的规范(Servlet、JSP、EL、WebSocket)。Tomcat 中的所有其他类加载器都遵循通常的委托模式。
因此,从 Web 应用程序的角度来看,类或资源加载按以下顺序查看以下存储库
- JVM 的引导类
- Web 应用程序的 /WEB-INF/classes
- Web 应用程序的 /WEB-INF/lib/*.jar
- 系统类加载器类(如上所述)
- 通用类加载器类(如上所述)
如果 Web 应用程序类加载器配置为 配置 为 <Loader delegate="true"/>
,则顺序变为
- JVM 的引导类
- 系统类加载器类(如上所述)
- 通用类加载器类(如上所述)
- Web 应用程序的 /WEB-INF/classes
- Web 应用程序的 /WEB-INF/lib/*.jar
XML 解析器和 Java
在较旧版本的 Tomcat 中,您可以简单地替换 Tomcat 库目录中的 XML 解析器,以更改所有 Web 应用程序使用的解析器。但是,当您运行现代版本的 Java 时,此技术将无效,因为通常的类加载器委托过程始终会优先选择 JDK 中的实现,而不是此实现。
Java 支持一种称为可升级模块的机制,允许替换 JCP 之外创建的 API(例如来自 W3C 的 DOM 和 SAX)。它还可以用于更新 XML 解析器实现。
请注意,覆盖任何 JRE 组件都存在风险。如果覆盖组件未提供 100% 兼容的 API(例如,Xerces 提供的 API 与 JRE 提供的 XML API 不完全兼容),则 Tomcat 和/或部署的应用程序可能会出现错误。
在安全管理器下运行
在安全管理器下运行时,允许加载类的位置还将取决于策略文件的内容。有关更多信息,请参阅 安全管理器操作指南。
高级配置
还可以配置更复杂的类加载器层次结构。请参阅下面的图表。默认情况下,服务器和共享类加载器未定义,并使用上面显示的简化层次结构。通过在 conf/catalina.properties
中为 server.loader
和/或 shared.loader
属性定义值,可以使用此更复杂的层次结构。
Bootstrap
|
System
|
Common
/ \
Server Shared
/ \
Webapp1 Webapp2 ...
服务器类加载器仅对 Tomcat 内部可见,对 Web 应用程序完全不可见。
共享类加载器对所有 Web 应用程序可见,可用于在所有 Web 应用程序之间共享代码。但是,对该共享代码的任何更新都需要重新启动 Tomcat。