Tomcat学习笔记


title: tomcat源码学习日志
date: 2018-07-07 23:32:43
tags:
- tomcat
- 源码学习
categories: 技·术

Tomcat是什么

Tomcat是ServletJSP、java EL表达式、WebSocket的实现。

Tomcat 7.0实现了Servlet 3.0JSP 2.2。提供了更多feature来开发和部署web应用和web服务。

官方资源汇总

编译源码

  • 下载Tomcat7源码
  • 配置JDK1.6
  • 配置1.9.x版本的Ant
  • 将build.xml中的base-apache.loc.1=https://www.apache.org/dyn/closer.lua?action=download&filename=替换为base-apache.loc.1=https://archive.apache.org/dist
  • 在tomcat目录下执行ant

源码阅读日志

整体理解

  • 主类/主方法:org.apache.catalina.startup包下的Bootstrap类。
  • 几个重要的目录(或者说环境变量):
主目录 含义
{ $CATALINA_HOME } Tomcat安装目录
{ $CATALINA_BASE } 每个实例分别的根目录(可选,默认情况等同于{ $CATALINA_HOME })
CATALINA_HOME
    ├─bin       // 诸如启动、停止等脚本。
    ├─conf      // 配置文件
    ├─logs      // 默认日志文件路径
    └─webapps   // web应用路径

架构理解

名称 意义
Server 代表整个容器。用户基本不会变动它。提供了Server接口。
Service 作为一个生存在Server中的组件,将许多Connector与一个Engine连接,起媒介作用。
Engine 代表某个Service的请求过程。一个Service连接着多个ConntectorEngine接收这些Connector的请求,处理请求,并返回。提供了Engine接口。
Host 一个Tomcat可包含多个域名,Host则维护这些域名。t提供了Host接口和完善的实现。
Connector 用于处理与客户端的通信。如Http Connector
Context 代表一个Web应用。一个Host包含多个Context,分别处于唯一的路径。提供了Context和完善的实现。

按照以上概念可以绘图:

启动步骤

根据官方文档,tomcat启动序列分为两个步骤:1)从命令行启动 2)处理命令行参数

一、从命令行启动

类:org.apache.catalina.startup.Bootstrap

执行内容:

  1. 安装一系列classLoader
  2. (以反射)读取启动类;
  3. 完成Bootstrap.daemon.init()方法。

二、处理命令行参数(start,stop)

类:org.apache.catalina.startup.Bootstrap

执行内容(start):

  1. Catalina.setAwait(true)
  2. Catalina.load():
    1. 初始化基本文件夹:initDirs() -> 设置诸如catalina.home/case等属性;
    2. 初始化命名服务:setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,org.apache.naming.java.javaURLContextFactory ->default)
    3. 创建xml文件转化器:createStartDigester()
    4. 读取server.xml并用转化器(digester)将其解析。digester是一个“XML-对象”映射器,将根据server.xml定义的内容创建对象。到目前为止,容器其实还没有开始初始化。
    5. System.outSystem.err分配给SystemLogHandler类。
    6. 调用所有组件的初始化方法。此步骤将令每个对象通过JMX代理注册其本身。在此步骤中,Connector也将初始化适配器。适配器也是一种组件,用来执行请求预处理。例如HTTP1.1适配器:org.apache.coyote.http11.Http11Protocol
  3. Catalina.start():
    1. 启动NamingContext,将所有JNDI引用绑定其中。
    2. 启动Server下的所有service。此步骤启动引擎(Engine)。
    3. 启动主机:StandardHost
      1. 配置一个错误阀门,用于将不同的HTTP错误码为HTML。
      2. 设置标准主机阀门,将web应用的类加载器与线程上下文绑定,它也用来为请求找到相应的session
      3. 启动HostConfig组件。此组件部署所有web应用,即webappconf/Catalina/localhost/*.xml
      4. HostConfig将为上下文创建一个Digester,它将调用ContextConfig.start()。这个方法将处理默认的web.xmlconf/web.xml,然后处理所有的应用web.xmlWEB-INF/web.xml
    4. 在容器的生命周期中,存在一个后台线程,用来不断检查上下文(context)是否改变,即war文件、context文件、web.xml文件等的改变。如果改变,则重新加载。(stop/remove/deploy/start
  4. 当Tomcat(在HTTP端口)接收到一个请求时:
    1. 该请求将被一个独立的线程接收。此线程在ThreadPoolExecutor类中。它在一个ServerSocket.accpet()方法中等待请求。
    2. ThreadPoolExecutor分配一个TaskThread来处理此请求。
    3. 处理器(processor)处理该请求。如果是HTTP请求,则是Coyote Http11Processor来处理。调用了process方法。此处理器将继续检查socket的输入流,直到连接断开,或者达到keep alive point
    4. 此HTTP请求将被内部的缓冲类(Http11InputBuffer)解析。此解析类将解析出请求行、请求头等等,将结果存储在一个Coyote请求中。此request包含所有的HTTP信息,如servernameportscheme等。
    5. 处理器维护着一个Adapter(引用),在本例中是CoyoteAdapter。一旦请求已经被解析,那么Http11Processor调用该adapterservice()方法。在此service方法中,Request包含一个CoyoteRequest和一个CoyoteResponse(第一次则为null)。CoyoteRequest(Response)实现了HttpRequest(Response)HttpServletRequest(Response)。适配器通过Mapper来处理requestcontext等。
    6. 当解析完成之后,CoyoteAdapter调用它的容器(StandardEngine),调用所有的invoke()方法。
    7. StandardEngine.invoke()方法调用容器的pipeline.invoke()方法。
    8. StandardHostValve调用与request相关的context上的pipeline
    9. Context pipeline调用的第一个阀门是FormAuthenticator阀门。接下来是StandardContextValveStandardContextValve调用与context相关的所有上下文监听器。然后调用Wrapper组件的所有pipeline
    10. 编译JSP,调用实际的servlet
  5. servlet类的调用

优美代码

观察到,一个典型的类中,可以被分成:

    // ------------------------------------------------------- Static Variables
    // -------------------------------------------------------------- Variables
    // -------------------------------------------------------- Private Methods
    // ----------------------------------------------------------- Main Program

典型的生命周期方法有:

    public void init()
    public void init(String[] arguments)
    public void start()
    public void stop()
    public void stopServer()
    public void stopServer(String[] arguments)
    public void destroy()
原文地址:https://www.cnblogs.com/liyeliang/p/9338858.html