首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Tomcat技术知识点总结

Tomcat技术知识点总结

作者头像
剑影啸清寒
发布2020-07-10 11:21:19
发布2020-07-10 11:21:19
7750
举报
文章被收录于专栏:琦小虾的Binary琦小虾的Binary

参考地址: 《tomcat架构》 《四张图带你了解Tomcat系统架构》

一. Tomcat 的结构

一个 Tomcat 中有一个 Server,每个 Server 中至少有一个 Service一个 Service 由至少一个 Connector 与一个 Container 组成

Service 的结构主要可以被分为两部分:ConnectorContainer

  • Connector: 用于接受客户端传来的数据,解析其协议,将解析后的数据传输给 Servlet;
  • Container: 封装和管理 Servlet,接收传来的请求,并完成处理逻辑;

1.1 Connector

一个 Connector 又由三部分组成:EndPoint, Processor, Adapter

  • EndPoint: 监听 TCP 请求,处理监听到的 socket;
    • Acceptor: 调用方法 accept() 监听 TCP 请求,捕获 socket;
    • Handler: 处理接收到的 socket;
  • Processor: 将 socket(TCP 协议,传输层) 转为 HttpRequest(HTTP 协议,应用层);
  • Adapter: 将 HttpRequest 传给 Servlet 容器,进行逻辑处理;

1.2 Container

Container 用来封装和管理 Servlet,并处理逻辑过程。Container 被分为四种类型:

  • Engine: 引擎,一个 Service 只有一个 Engine,可以管理多个站点 host;
  • Host: 站点,或者成为虚拟主机;
  • Context: 应用上下文
    • 通常对应着 webapp 目录下的一个文件夹;
    • 一个 host 可以有多个 context;
  • Wrapper: 每一个 wrapper 对应一个 Servlet;

根据 Tomcat 的文件目录可以对照几个 Container 的内容:

由于 Container 是一个实现了 LifeCycle 的接口,LifeCycle 接口中包含了初始化 init(), start(), stop(), destroy() 方法(生命周期方法),所以 engine, host, context, wrapper 都需要实现自己的生命周期方法。 四种类型的 Container 是通过组合的方式进行调用的。具体关系见下文的 Tomcat 启动流程。

二. Tomcat 如何处理请求?

首先客户端发送请求,被 Connector 捕获,处理为 HTTP 请求,发送到 Container。Container 使用责任链进行处理; 责任链可以理解为 Engine, Host, Context, Wrapper 四条 Pipeline 串行后的一条链,传入的请求首先传入 EnginePipeline 的第一个 Engine,最后传到 WrapperPipeline 的最后一个 Wrapper(StandardWrapperValue)。 值得一提的是,执行到最后的 StandardWrapperValue 时,会创建一个 FilterChain 用于匹配我们创建的 Filter 和 Servlet。FilterChain 的作用是通过其 doFilter 方法依次调用:

  1. 所有 Fitler#doFilter() 方法;
  2. 所有 servlet#service() 方法;

经过这样一系列链式处理,请求处理完毕,即可将结果通过响应 Response 返回给客户端。

三. Tomcat 容器、Spring 容器、Servlet 容器、SpringMVC 容器的关系与区别

3.1 Tomcat 的启动

参考地址: 《Tomcat启动过程源码解读》

Tomcat 启动的时序图如下所示:

Tomcat 启动的入口类:org.apache.catalina.startup.Bootstrap#main

在 main 方法中调用 bootstrap#init() 方法,其中通过反射的方式初始化 Catalina 类,然后调用 Catalina 的 start() 方法,Tomcat 开始启动:

代码语言:javascript
复制
public void start() {
 
    if (getServer() == null) {
        load();
    }
 
    if (getServer() == null) {
        log.fatal("Cannot start server. Server instance is not configured.");
        return;
    }
 
    long t1 = System.nanoTime();
 
    // Start the new server
    try {
        getServer().start();
    } catch (LifecycleException e) {
        log.fatal(sm.getString("catalina.serverStartFail"), e);
        try {
            getServer().destroy();
        } catch (LifecycleException e1) {
            log.debug("destroy() failed for failed Server ", e1);
        }
        return;
    }
 
    long t2 = System.nanoTime();
    if(log.isInfoEnabled()) {
        log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms");
    }
 
    // Register shutdown hook
    if (useShutdownHook) {
        if (shutdownHook == null) {
            shutdownHook = new CatalinaShutdownHook();
        }
        Runtime.getRuntime().addShutdownHook(shutdownHook);
 
        // If JULI is being used, disable JULI's shutdown hook since
        // shutdown hooks run in parallel and log messages may be lost
        // if JULI's hook completes before the CatalinaShutdownHook()
        LogManager logManager = LogManager.getLogManager();
        if (logManager instanceof ClassLoaderLogManager) {
            ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                    false);
        }
    }
 
    if (await) {
        await();
        stop();
    }
}

Catalina#start() 方法中的调用流程:

  1. server#start() -> StandardServer#startInternal();
    • 遍历当前 server 的所有 service,逐个调用 service#start();
  2. service#start() -> StandardService#startInternal();
    • 执行当前 service 的 engine 的 start() 方法;
  3. engine#start() -> StandardEngine#startInternal();
    • 遍历当前 engine 的所有 host,逐个调用 host#start();
  4. host#start() -> StandardHost#startInternal();
    • 遍历当前 host 的所有 context,逐个调用 context#start();
  5. context#start() -> StandardContext#startInternal();
    • 遍历当前 context 的所有 wrapper,逐个调用 wrapper#start();
    • 在 StandardContext#startInternal() 执行过程中,会调用 listenerStart() 方法,该方法中会发布容器初始化完毕事件 ServletContextEvent,包括 ContextLoaderListener 在内的监听器接受到该事件之后进行响应;SpringMVC 就是在接收到该事件之后开始进行 SpringMVC 容器的初始化的

3.2 Tomcat 启动 Spring MVC 的过程

Tomcat 启动过程中会调用 org.apache.catalina.core.StandardContext # listenterStart() 方法,方法过程中会调用 listener.contextInitialized(event) 方法,其中的 event 类型是 ServletContextEvent。即 Tomcat 在启动时,会发送容器初始化事件。 通常在使用 Spring MVC 进行 web 部署时,web.xml 里面经常配置的一个监听器 ContextLoaderListenr,如下所示:

代码语言:javascript
复制
<listener>  
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
</listener>

这个 ContextLoaderListener 就在这时候监听到该事件,于是配合 web.xml 中其他的配置项,执行 Spring 容器和 SpringMVC 容器的初始化。其他配置项如下:

代码语言:javascript
复制
<context-param>  
    <!-- 用来指定 Spring 需要加载的配置文件 -->
    <param-name>contextConfigLocation</param-name>  
    <param-value>/WEB-INF/dispatcherServlet-servlet.xml</param-value>  
</context-param>  
  
<!-- Spring MVC -->  
<servlet>  
    <servlet-name>dispatcherServlet</servlet-name>  
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
    <load-on-startup>1</load-on-startup>  
</servlet>  
<servlet-mapping>  
    <servlet-name>dispatcherServlet</servlet-name>  
    <url-pattern>*.action</url-pattern>  
</servlet-mapping>

配合 ContextLoaderListener 一起使用的,经常是 context-param,用来指定 Spring 需要加载的配置文件;而下面的 servlet 指定了 DispatcherServlet 作为具体的 Servlet 实现类,DispatcherServlet 是 SpringMVC 的核心调度器。dispatcherServlet-servlet.xml 中存储了配置 SpringMVC 的视图解析器等信息。

回到前面调用 ContextLoaderListener#contextInitialized 方法,观察源码可知主要的方法实现还是在 ContextLoader#initWebApplicationContext() 方法中。该方法的主要功能,就是创建一个 WebApplicationContext,并将其存入Tomcat WEB 应用的唯一全局上下文环境 ServletContext 中

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/07/09 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一. Tomcat 的结构
    • 1.1 Connector
    • 1.2 Container
  • 二. Tomcat 如何处理请求?
  • 三. Tomcat 容器、Spring 容器、Servlet 容器、SpringMVC 容器的关系与区别
    • 3.1 Tomcat 的启动
    • 3.2 Tomcat 启动 Spring MVC 的过程
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档