内容

目录

通用

请首先阅读通用的迁移指南页面,了解适用于 Apache Tomcat® 不同版本之间迁移或升级的常见注意事项。

从 7.0.x 迁移到 8.0.x

本节列出了 7.0.x 和 8.0.x 之间所有已知可能在升级时导致向后兼容性问题的更改。

需要 Java 7

Apache Tomcat 8.0.x 需要 Java 7 或更高版本。Apache Tomcat 7.0.x 需要 Java 6。

规范 API

Apache Tomcat 8 支持 Java Servlet 3.1、JavaServer Pages 2.3、Java 统一表达式语言 3.0 和 Java WebSocket API 1.1 规范。规范版本之间的更改可在每个规范文档的“更改”附录中找到。

Servlet 3.1 API

在使用通配符导入语法的 JSP 页面中,Servlet API 中新增的类可能与 Web 应用程序中的类发生冲突。例如,如果包 "a" 包含类 ReadListener,则以下 JSP 页面将在 Tomcat 8 中停止编译:

<%@page import="a.*"%>
<% ReadListener listener = new ReadListener(); %>

发生这种情况是因为 javax.servlet.* 的隐式导入和 a.* 的显式导入将提供在 Servlet 3.1 中添加的 ReadListener 类的冲突定义。解决方案是使用显式导入,即 import="a.ReadListener"

JavaServer Pages 2.3

统一表达式语言 3.0 增加了对引用静态字段和方法的支持。在 JSP 中支持此功能需要更改 javax.servlet.jsp.el.ScopedAttributeELResolver 实现,使其也检查标识符是否为导入类或字段的名称。在某些情况下,此更改会导致显著的性能下降。这会影响可能引用页面、请求、会话或应用程序范围变量的标识符,或可能未定义的标识符。当未定义时,解析标识符需要更长的时间,因为它现在还会被检查是否为导入的类或字段。为避免此性能下降,像这样的代码:

${undefined}

应替换为

${requestScope.undefined}

或类似形式,使用变量定义的适当作用域。

Jar 扫描

在实现 Servlet 3.1 期间,Tomcat 7 的 Servlet 3.0 可插拔性实现中发现了一些错误。具体来说,

  • SCI 扫描不遵守类加载器顺序;
  • 容器 JAR 中的片段被处理而不是被忽略;
  • 容器提供的 SCI 有时被忽略。

这些问题已在 Tomcat 8 中得到纠正,但未回溯到 Tomcat 7,因为修复需要对 JarScanner 组件进行重大的 API 更改以及对配置选项进行更改。

迁移到 Tomcat 8 时,需要审查 Jar 扫描配置并根据新的配置选项进行调整,并且自定义 JarScanner 实现将需要更新以实现新的 API。

默认连接器实现

默认的 HTTP 和 AJP 连接器实现已从 Java 阻塞 IO 实现 (BIO) 切换到 Java 非阻塞 IO 实现 (NIO)。BIO 仍然可以使用,但使用非阻塞 IO 的 Servlet 3.1 和 WebSocket 1.0 功能将转而使用阻塞 IO,这可能会导致意外的应用程序行为。

默认 URL 编码

HTTP 和 AJP 连接器的 URIEncoding 属性的默认值已从“ISO-8859-1”更改为“UTF-8”(如果“严格 Servlet 兼容性”模式关闭,这是默认设置)。此设置指定用于解码请求 URI 路径和查询中“%xx”编码字节的字符编码。

如果服务器配置为启用“严格 Servlet 兼容性”,则连接器的 URIEncoding 属性的默认值为“ISO-8859-1”,与旧版本 Tomcat 相同。

参考:HTTP 连接器AJP 连接器

Realm 域

摘要密码的处理已移至新的 CredentialHandler 组件。相关的 Realm 属性在 8.0.x 中仍然有效,但它们已被弃用,并已从 Tomcat 8.5.x 及更高版本中移除。

Web 应用程序资源

Aliases、VirtualLoader、VirtualDirContext、JAR 资源和外部存储库功能都提供了向 Web 应用程序添加资源的方式,它们已被一个统一的框架取代,而不是各自独立实现(这变得越来越难以维护)。资源文档详细说明了如何使用新实现。

资源的重构还导致从默认的 Context 实现 (org.apache.catalina.core.StandardContext) 中移除了许多属性。以下属性现在可以通过 Web 应用程序使用的 资源 实现进行配置:

  • allowLinking
  • cachingAllowed
  • cacheMaxSize
  • cacheObjectMaxSize
  • cacheTtl (已重命名:在 Tomcat 7 中是 cacheTTL)

例如,Tomcat 7 和 Tomcat 8 中的配置

<!-- Tomcat 7: -->
<Context allowLinking="true" />

<!-- Tomcat 8: -->
<Context>
  <Resources allowLinking="true" />
</Context>

数据库连接池

Tomcat 8 和 Tomcat 7 一样,都附带了两种数据库连接池的实现。第一种实现(默认实现;尽管技术上可以通过 javax.sql.DataSource.Factory 系统属性进行更改)是 Apache Commons DBCP 2.x 项目的副本,并已重命名为不同的包。第二种实现是 Tomcat JDBC 连接池,一个独立的项目。

Apache Commons DBCP 1.x(Tomcat 7 及更早版本使用)和 Apache Commons DBCP 2.x 之间存在一些显著变化,这些变化可能需要修改配置。

  • maxActive 配置选项已重命名为 maxTotal
  • maxWait 配置选项已重命名为 maxWaitMillis
  • JDBC 驱动程序 JAR 可以放置在 WEB-INF/lib 中,作为 $CATALINA_BASE/lib 的替代方案,前提是驱动程序类仅由该 Web 应用程序使用。
  • 连接验证不再要求同时设置验证查询和至少一个 testXxx 属性为 true。如果未定义验证查询且至少一个 testxxx 属性为 true,则连接将使用 Connection.isValid() 进行验证。
  • removeAbandoned 配置选项已被 removeAbandonedOnBorrowremoveAbandonedOnMaintenance 取代。

此外,Commons DBCP 还添加了许多新的配置选项。应审查这些选项,以确定应使用哪些(如果有的话)。

请注意,如果您正在使用 Tomcat JDBC 连接池(或任何第三方数据库连接池实现),则不需要上述更改。

集群

Servlet 3.1 中添加的 HttpServletRequest.changeSessionId() 方法使得 org.apache.catalina.ha.session.JvmRouteSessionIDBinderListener 变得不必要,因此它已被移除。升级到 Tomcat 8 时,必须将其从集群配置中移除。

调试

当使用 jpda 选项启动 Tomcat 以启用远程调试时,Tomcat 8 默认监听 localhost:8000。早期版本监听 *:8000。如果需要,可以通过在例如 setenv.[bat|sh] 中设置 JPDA_ADDRESS 环境变量来覆盖此默认值。

内部 API

虽然 Tomcat 8 内部 API 与 Tomcat 7 大致兼容,但在细节层面存在许多更改,并且它们不具备二进制兼容性。与 Tomcat 内部交互的自定义组件开发人员应查阅相关 API 的 JavaDoc。

特别值得注意的是:

  • Manager、Loader 和 Resources 已从 Container 移至 Context,因为 Context 是它们唯一被使用的地方。
  • Mapper 已从 Connector 移至 Service,因为 Mapper 对于给定 Service 的所有 Connector 都是相同的。
  • 一个新的 Resources 实现,将 Aliases、VirtualLoader、VirtualDirContext、JAR 资源和外部存储库合并到一个单一框架中,而不是为每个功能单独实现。
  • 新增了一个 SessionIdGenerator 接口,使会话 ID 生成可扩展。Manager 接口中已添加获取和设置 ID 生成器类名的方法。

部署

将 Web 应用程序部署为 WAR 文件并配置 Tomcat 不解压 WAR 文件,将导致启动时间显著变慢,并降低运行时性能。启动时间已测量为慢三到十倍。运行时影响将很大程度上取决于应用程序结构。

强烈建议不要在 Host 上设置 unpackWARs="false" 或在 Context 上设置 unpackWAR="false"。以下是禁用解压的常见原因以及 Tomcat 8 的推荐替代方案:

  • 安全性(appBase 对 Tomcat 用户只读) - 部署(以不同用户)一个已解压的目录到 appBase,而不是 WAR 文件。
  • 在多个主机之间共享 appBase - 将 WAR 文件部署到公共位置,然后使用 context.xml 文件按需将 Web 应用程序添加到主机。请注意,在任何情况下都强烈不建议在多个主机之间共享 appBase。
  • 离线部署 - 从 Tomcat 8.0.21 开始,Tomcat 将检测到在它未运行时 WAR 文件是否已更新,并在下次启动时移除过时的已展开目录并部署更新的 WAR 文件,因此只需使用 unpackWAR="true" 并在 Tomcat 未运行时继续部署 WAR 文件即可。

升级 8.0.x

当将 Apache Tomcat 实例从 Tomcat 8 的一个版本升级到另一个版本时,特别是在为 $CATALINA_HOME 和 $CATALINA_BASE 使用不同位置时,需要确保将配置文件中的任何更改(例如新属性和默认值的更改)作为升级的一部分应用。为了帮助识别这些更改,可以使用以下表格查看 Tomcat 8 不同版本之间配置文件的差异。

Tomcat 8.0.x 显著变化

Tomcat 开发者致力于使每个补丁版本都完全向后兼容上一个版本。偶尔,为了修复错误,有必要破坏向后兼容性。在大多数情况下,这些更改不会被注意到。本节列出了并非完全向后兼容并可能在升级时导致故障的更改。

  • 从 8.0.24 开始,连接器上 maxPostSize 属性值 0 的含义已更改为表示零限制而不是无限制,以使其与 maxSavePostSize 对齐并更直观。

    参考:HTTP 连接器AJP 连接器

Tomcat 8.0.x 配置文件差异

从下面的框中选择一个配置文件、旧版本和新版本,然后单击“查看差异”以查看差异。差异将在新选项卡/窗口中显示。

您还可以使用类似于以下内容的 Subversion 命令(全部在一行)

svn diff
  --old=http://svn.apache.org/repos/asf/tomcat/archive/tc8.0.x/tags/TOMCAT_8_0_1/conf/
  --new=http://svn.apache.org/repos/asf/tomcat/archive/tc8.0.x/tags/TOMCAT_8_0_3/conf/