Jakarta Servlet API 定义服务器端请求和响应模型。Apache Tomcat 实现该 API,
并提供 Catalina servlet 容器、HTTP 和 AJP 连接器、会话管理、部署和运维工具。
Tomcat 11 实现 Jakarta Servlet 6.1 并需要 Java 17;导入 javax.servlet.* 的旧应用
需要迁移到 jakarta.servlet.* 命名空间,或使用较旧的兼容容器。
Web 应用布局 #
可部署的 Web 应用可以是展开目录或 WAR 归档:
orders.war
|-- index.html
`-- WEB-INF
|-- web.xml
|-- classes/com/example/OrdersServlet.class
`-- lib/orders-domain.jarWEB-INF/ 下的资源不能由客户端直接寻址。WEB-INF/classes/ 包含应用类和资源,
WEB-INF/lib/ 包含依赖 JAR。WEB-INF/web.xml 是部署描述符。
Servlet 3.0 及更高版本还支持基于注解的注册,以及通过 ServletContainerInitializer 进行程序化注册,
因此除非部署需要描述符元数据或排序,否则可以省略 web.xml。
映射和请求分派 #
Servlet 映射根据 URL 模式选择 servlet。精确映射优先于最长路径映射,
随后是扩展名映射和默认 / 映射。过滤器可以在目标之前或之后包装请求和响应,
监听器则观察上下文、会话和请求生命周期事件。
分派具有不同的 DispatcherType 值:
REQUEST表示原始容器分派。FORWARD在不经过客户端往返的情况下转移处理。INCLUDE插入另一个资源的输出。ERROR调用配置的错误处理。ASYNC继续处理异步请求。
request.getRequestDispatcher("/WEB-INF/views/order.jsp")
.forward(request, response);重定向则发送 3xx 响应,之后客户端开始新请求。在正常分派期间,连接器解析请求, Catalina 选择虚拟主机和 Web 上下文,过滤器链运行,一个 servlet 实例处理调用。 容器会并发调用 servlet,因此可变实例字段需要同步,或者最好完全消除。
会话通过 Cookie 或 URL 重写标识。并发请求可能访问会话属性,不能将它们视为线程私有。
异步处理会释放请求线程,但应用必须完成 AsyncContext,并保留所需的安全或日志上下文。
Tomcat 的容器模型 #
org.apache.catalina.startup.Bootstrap 启动独立安装。
catalina.home 指向共享的 Tomcat 二进制文件,而 catalina.base 指向实例的配置、日志、
临时文件、工作目录和已部署应用。因此多个实例可以共享一个安装。
Catalina 组合以下元素:
Server拥有 Tomcat 实例。Service将一个或多个Connector与一个Engine关联。Engine将请求路由到Host。Host包含一个或多个 Web 应用Context。Wrapper表示单个 servlet。
连接器负责协议处理和工作线程。阻塞式 servlet 工作会占用这些线程, 因此连接器限制、下游超时和应用执行器限制必须形成一个统一的容量计划。
类加载器和关闭 #
Tomcat 分离引导、系统、公共和每个 Web 应用的类加载器。
Web 应用可以看到自己的 WEB-INF/classes 和 WEB-INF/lib,但看不到其他应用的类。
Tomcat 的 Web 加载器对应用类使用本地优先查找,但对 Java、Jakarta Servlet 和容器实现 API
必须委派。WEB-INF/lib 中重复的 API JAR 不会覆盖容器 API,并可能导致链接失败。
为实现优雅关闭,停止接受新流量,在截止时间内允许进行中的工作完成,然后停止 Server。
Servlet 上下文监听器和受管资源会收到关闭回调,但应用创建的执行器和线程仍需要显式终止。
会话持久化取决于配置的管理器,不得假设重启后仍然存在。
评论
在 GitHub 上阅读或评论(发表评论需要登录)