Tomcat Architecture Analysis

Introduction

Apache Tomcat软件是Java Servlet、JavaServer Pages、Java Expression Language和Java WebSocket技术的一个开源实现。Java Servlet、JavaServer Pages、Java Expression Language和Java WebSocket规范是在Java Community Process下开发的。

简单来说,Tomcat可以看成是Web服务器加Servlet容器。

在上面的流程图中,Tomcat通过Connector组件接收并解析HTTP请求,将ServletRequest对象发送给Container进行处理。Container处理完成后会将响应封装成ServletRespone对象返回给Connector,然后Connector再将ServletRespone对象解析成HTTP响应文本格式发送给客户端,至此Tomcat就完成了一次网络通信。

Architecture

在Tomcat架构图中主要包含三个组件:Service、Connectot、Container。

  • Server:Web服务器,一个Server中可以包含多个Service。
  • Service:每一个Service都是独立的,它们共享一个JVM以及系统类库,并且一个Service负责维护多个Connector和一个Container。
  • Connector:Connector用于连接Service和Container,解析客户端的请求并转发到Container,以及转发来自Container的响应。每一种不同的Connector都可以处理不同的请求协议,包括HTTP/1.1、HTTP/2、AJP等等。
  • Container:Tomcat的Container包含四种子容器,分别为Engine、Host、Context和Wrapper。其中,一个Container对应一个Engine,一个Engine可以包含多个Host,一个Host可以包含多个Context,一个Context又包含多个Wrapper。
    • Engine:可以看成是容器对外提供功能的入口,每个Engine是Host的集合,用于管理各个Host。
    • Host:可以看成一个虚拟主机,一个Tomcat可以支持多个虚拟主机。虚拟主机的作用就是运行多个应用,它负责安装和展开这些应用,并且标识这个应用以便能够区分它们,每个虚拟主机对应的一个域名,不同Host容器接受处理对应不同域名的请求。
    • Context:上下文容器,可以将其看成一个Web应用,每个Host里面可以运行多个Web应用。同一个Host里面不同的Context,其contextPath必须不同,默认Context的contextPath为空格或斜杠。
    • Wrapper:对Servlet的抽象和包装,每个Context可以有多个Wrapper,用于支持不同的Servlet,每个Wrapper实例表示一个具体的Servlet定义,Wrapper主要负责管理Servlet,包括Servlet的装载、初始化、执行以及资源回收。

下图展示了请求在Container中的解析过程:

Three Major Components

Java Web中有三大组件,分别是Servlet、Filter和Listener。三者的加载顺序为Listener->Filter->Servlet。

在org.apache.catalina.core.StandardContext类的startInternal方法中,首先调用了listenerStart,接着是filterStart,最后是loadOnStartup。这三处调用分别触发了Listener、Filter、Servlet的构造加载。

Listener

Conception

Listener是一个实现了特定接口的Java程序,用于监听一个方法或者属性,当被监听的方法被调用或者属性改变时,就会自动执行某个方法。

与Listener相关的概念:

  • 事件:某个方法被调用,或者属性的改变;
  • 事件源:被监听的对象(如ServletContext、requset、方法等);
  • 监听器:用于监听事件源,当发生事件时会触发监听器。

监听器分类:

事件源 监听器 描述
ServletContext ServletContextListener 用于监听 ServletContext 对象的创建与销毁过程
HttpSession HttpSessionListener 用于监听 HttpSession 对象的创建和销毁过程
ServletRequest ServletRequestListener 用于监听 ServletRequest 对象的创建和销毁过程
ServletContext ServletContextAttributeListener 用于监听 ServletContext 对象的属性新增、移除和替换
HttpSession HttpSessionAttributeListener 用于监听 HttpSession 对象的属性新增、移除和替换
ServletRequest ServletRequestAttributeListener 用于监听 HttpServletRequest 对象的属性新增、移除和替换
HttpSession HttpSessionBindingListener 用于监听 JavaBean 对象绑定到 HttpSession 对象和从 HttpSession 对象解绑的事件
HttpSession HttpSessionActivationListener 用于监听 HttpSession 中对象活化和钝化的过程

按照监听的对象不同将其划分为三类:ServletContextListener,HttpSessionListener和ServletRequestListener。

Usage

  • ServletContextListener配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.memoryshell.tomcatmemoryshell;

import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;

@WebListener
public class MemoryListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("ServletContext对象创建...");
}

@Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("ServletContext对象销毁...");
}
}
  • web.xml配置
1
2
3
4
5
6
7
8
9
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0">
<listener>
<listener-class>com.memoryshell.tomcatmemoryshell.MemoryListener</listener-class>
</listener>
</web-app>

Filter

Conception

Filter用于拦截用户请求以及服务端的响应,能够在拦截之后对请求和响应做出相应的修改。Filter不是Servlet,不能直接访问,它能够对于Web应用中的资源(Servlet、JSP、静态页面等)做出拦截,从而实现一些相应的功能。

Life Cycle

Filter的生命周期分为三个阶段:

  • 初始化阶段:Filter的初始化阶段只会在Web应用程序启动时调用一次。
  • 拦截和过滤阶段:当客户请求访问与过滤器关联的URL的时候,Servlet过滤器将先执行doFilter方法。FilterChain参数用于访问后续过滤器。
  • 销毁阶段:Filter的销毁阶段只会在web应用移除或服务器停止时才调用一次来卸载Filter对象。

Usage

  • FilterChain

一个Servlet可以注册多个Filter,Web容器会将注册的多个Filter组合成一个”Filter链”,并按照一定的顺序依次执行各Filter的doFilter方法。

  • Filter execution sequence

由于Filter的注册方式不同,其执行顺序也有所不同。

  1. 基于注解配置:按照类名的字符串比较规则比较,值小的先执行;
  2. 使用web.xml配置:根据对应的Mapping的顺序组织,谁定义在上边谁就在前。
  • FilterConfig

和Servlet类似,由于Filter也有可能访问Servlet,所以Servlet规范将代表ServletContext对象和Filter的配置参数信息都封装到一个称为FilterConfig的对象中。

FilterConfig接口则用于定义FilterConfig对象应该对外提供的方法,以便在Filter的doFilter方法中可以调用这些方法来获取ServletContext对象,以及获取在web.xml文件中的一些初始化参数。

Servlet

Conception

Servlet是运行在Web服务器或应用服务器上的程序,它是作为来自HTTP客户端的请求和HTTP服务器上的数据库或应用程序之间的中间层。用来处理客户端请求的动态资源,并根据请求生成相应的返回信息提供给用户,当Tomcat接收到来自客户端的请求时,会将其解析成RequestServlet对象并发送到对应的Servlet上进行处理。

Life Cycle

Servlet的生命周期分为五个阶段:

  • 加载阶段:当Tomcat第一次访问Servlet时,会创建Servlet的实例。
  • 初始化阶段:当Servlet实例化后,Tomcat会调用init方法初始化这个对象。
  • 处理服务阶段:当浏览器访问Servlet时,Servlet会调用service方法处理请求。
  • 销毁阶段:当Tomcat关闭时或者检测到Servlet要从Tomcat删除时,会自动调用destroy方法,让该实例释放掉所占的资源。除此之外,一个Servlet如果长时间不被使用的话,也会被Tomcat自动销毁。
  • 卸载阶段:当Servlet调用完destroy方法后,会等待垃圾回收。如果有需要再次使用这个Servlet时,会重新调用init方法进行初始化操作。

Usage

根据上文对Servlet生命周期的了解,当需要实现一个Servlet时,需要继承Servlet接口,并实现相应的五个方法。

在Tomcat中已经封装好了两个类,分别是GenericServlet类和HttpServlet类。GenericServlet抽象类实现了Servlet接口,并对Servlet接口中除service方法外的其它四个方法进行了简单实现。

通过继承GenericServlet类创建来Servlet,只需要重写service方法即可。但是,GenericServlet抽象类是一个通用的Servlet类,并不是针对某种应用场景而设计的,因此在处理HTTP请求的时候需要手动实现对HTTP请求的解析和封装。

HttpServlet是GenericServlet的子类,它在GenericServlet的基础上专门针对HTTP协议进行了处理。其针对每一种HTTP请求都设置了一种处理方法。当使用HttpServlet类的时候,只需要根据HTTP请求类型重写相应的处理方法即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@WebServlet(name = "MemoryServlet", value = "/MemoryServlet")
public class MemoryServlet extends HttpServlet {
private String message;

@Override
public void init() {
message = "This is MemoryShell page!";
}

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType("text/html");

// Hello
PrintWriter out = response.getWriter();
out.println("<html><body>");
out.println("<h1>" + message + "</h1>");
out.println("</body></html>");
}
}

Reference