• 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()
    
  • 相关阅读:
    Mysql Group by week
    查询数据库占用磁盘大小
    菜根谭#117
    菜根谭#116
    保护眼睛颜色的RGB数值
    手动释放linux内存和缓存
    菜根谭#115
    菜根谭#114
    菜根谭#113
    spring mvc静态资源文件的引用
  • 原文地址:https://www.cnblogs.com/liyeliang/p/9338858.html
Copyright © 2020-2023  润新知