加入收藏 | 设为首页 | 会员中心 | 我要投稿 三明站长网 (https://www.0598zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长资讯 > 外闻 > 正文

深入Tomcat 架构及启动过程「含部署」

发布时间:2019-05-28 12:08:31 所属栏目:外闻 来源:今日头条
导读:副标题#e# 这个题目命的其实是很大的,写的时候还是很忐忑的,但我尽可能把这个过程描述清楚。因为这是读过源码以后写的总结,在写的过程中可能会忽略一些前提条件,如果有哪些比较突兀就出现,或不好理解的地方可以给我提 Issue,我会尽快补充修订相关内容
副标题[/!--empirenews.page--]

这个题目命的其实是很大的,写的时候还是很忐忑的,但我尽可能把这个过程描述清楚。因为这是读过源码以后写的总结,在写的过程中可能会忽略一些前提条件,如果有哪些比较突兀就出现,或不好理解的地方可以给我提 Issue,我会尽快补充修订相关内容。

很多东西在时序图中体现的已经非常清楚了,没有必要再一步一步的作介绍,所以本文以图为主,然后对部分内容加以简单解释。

绘制图形使用的工具是 PlantUML + Visual Studio Code + PlantUML Extension

深入Tomcat 架构及启动过程「含部署」

图形 PlantUML 源文件:

  • tomcat-architecture.pu
  • tomcat-init.pu
  • tomcat-start.pu
  • tomcat-context-start.pu
  • tomcat-background-thread.pu

本文对 Tomcat 的介绍以 Tomcat-9.0.0.M22 为标准。

Tomcat-9.0.0.M22 是 Tomcat 目前最新的版本,但尚未发布,它实现了 Servlet4.0 及 JSP2.3 并提供了很多新特性,需要 1.8 及以上的 JDK 支持等等,详情请查阅 Tomcat-9.0-doc

Tomcat-9.0-dochttps://tomcat.apache.org/tomcat-9.0-doc/index.html

Overview

深入Tomcat 架构及启动过程「含部署」
  1. Bootstrap 作为 Tomcat 对外界的启动类,在 $CATALINA_BASE/bin 目录下,它通过反射创建 Catalina 的实例并对其进行初始化及启动。
  2. Catalina 解析 $CATALINA_BASE/conf/server.xml 文件并创建 StandardServer、StandardService、StandardEngine、StandardHost 等
  3. StandardServer 代表的是整个 Servlet 容器,他包含一个或多个 StandardService
  4. StandardService 包含一个或多个 Connector,和一个 Engine,Connector 和 Engine 都是在解析 conf/server.xml 文件时创建的,Engine 在 Tomcat 的标准实现是 StandardEngine
  5. MapperListener 实现了 LifecycleListener 和 ContainerListener 接口用于监听容器事件和生命周期事件。该监听器实例监听所有的容器,包括 StandardEngine、StandardHost、StandardContext、StandardWrapper,当容器有变动时,注册容器到 Mapper。
  6. Mapper 维护了 URL 到容器的映射关系。当请求到来时会根据 Mapper 中的映射信息决定将请求映射到哪一个 Host、Context、Wrapper。
  7. Http11NioProtocol 用于处理 HTTP/1.1 的请求
  8. NioEndpoint 是连接的端点,在请求处理流程中该类是核心类,会重点介绍。
  9. CoyoteAdapter 用于将请求从 Connctor 交给 Container 处理。使 Connctor 和 Container 解耦。
  10. StandardEngine 代表的是 Servlet 引擎,用于处理 Connector 接受的 Request。包含一个或多个 Host(虚拟主机), Host 的标准实现是 StandardHost。
  11. StandardHost 代表的是虚拟主机,用于部署该虚拟主机上的应用程序。通常包含多个 Context (Context 在 Tomcat 中代表应用程序)。Context 在 Tomcat 中的标准实现是 StandardContext。
  12. StandardContext 代表一个独立的应用程序,通常包含多个 Wrapper,一个 Wrapper 容器封装了一个 Servlet,Wrapper的标准实现是 StandardWrapper。
  13. StandardPipeline 组件代表一个流水线,与 Valve(阀)结合,用于处理请求。 StandardPipeline 中含有多个 Valve, 当需要处理请求时,会逐一调用 Valve 的 invoke 方法对 Request 和 Response 进行处理。特别的,其中有一个特殊的 Valve 叫 basicValve,每一个标准容器都有一个指定的 BasicValve,他们做的是最核心的工作。
  • StandardEngine 的是 StandardEngineValve,他用来将 Request 映射到指定的 Host;
  • StandardHost 的是 StandardHostValve, 他用来将 Request 映射到指定的 Context;
  • StandardContext 的是 StandardContextValve,它用来将 Request 映射到指定的 Wrapper;
  • StandardWrapper 的是 StandardWrapperValve,他用来加载 Rquest 所指定的 Servlet,并调用 Servlet 的 Service 方法。

Tomcat init

深入Tomcat 架构及启动过程「含部署」
  • 当通过 ./startup.sh 脚本或直接通过 java 命令来启动 Bootstrap 时,Tomcat 的启动过程就正式开始了,启动的入口点就是 Bootstrap 类的 main 方法。
  • 启动的过程分为两步,分别是 init 和 start,本节主要介绍 init;
  • 初始化类加载器。[关于 Tomcat 类加载机制,可以参考我之前写的一片文章:谈谈Java类加载机制]
  1. 通过从 CatalinaProperties 类中获取 common.loader 等属性,获得类加载器的扫描仓库。CatalinaProperties 类在的静态块中调用了 loadProperties() 方法,从 conf/catalina.properties 文件中加载了属性.(即在类创建的时候属性就已经加载好了)。
  2. 通过 ClassLoaderFactory 创建 URLClassLoader 的实例
  • 通过反射创建 Catalina 的实例并设置 parentClassLoader
  • setAwait(true)。设置 Catalina 的 await 属性为 true。在 Start 阶段尾部,若该属性为 true,Tomcat 会在 main 线程中监听 SHUTDOWN 命令,默认端口是 8005.当收到该命令后执行 Catalina 的 stop() 方法关闭 Tomcat 服务器。
  • createStartDigester()。Catalina 的该方法用于创建一个 Digester 实例,并添加解析 conf/server.xml 的 RuleSet。Digester 原本是 Apache 的一个开源项目,专门解析 XML 文件的,但我看 Tomcat-9.0.0.M22 中直接将这些类整合到 Tomcat 内部了,而不是引入 jar 文件。Digester 工具的原理不在本文的介绍范围,有兴趣的话可以参考 The Digester Component – Apache 或 《How Tomcat works》- Digester [推荐] 一章
  • parse() 方法就是 Digester 处理 conf/server.xml 创建各个组件的过程。值的一提的是这些组件都是使用反射的方式来创建的。特别的,在创建 Digester 的时候,添加了一些特别的 rule Set,用于创建一些十分核心的组件,这些组件在 conf/server.xml 中没有但是其作用都比较大,这里做下简单介绍,当 Start 时用到了再详细说明:
  1. EngineConfig。LifecycleListener 的实现类,触发 Engine 的生命周期事件后调用,这个监听器没有特别大的作用,就是打印一下日志
  2. HostConfig。LifecycleListener 的实现类,触发 Host 的生命周期事件后调用。这个监听器的作用就是部署应用程序,这包括 conf/// 目录下所有的 Context xml 文件 和 webapps 目录下的应用程序,不管是 war 文件还是已解压的目录。 另外后台进程对应用程序的热部署也是由该监听器负责的。
  3. ContextConfig。LifecycleListener 的实现类,触发 Context 的生命周期事件时调用。这个监听器的作用是配置应用程序,它会读取并合并 conf/web.xml 和 应用程序的 web.xml,分析 /WEB-INF/classes/ 和 /WEB-INF/lib/*.jar中的 Class 文件的注解,将其中所有的 Servlet、ServletMapping、Filter、FilterMapping、Listener 都配置到 StandardContext 中,以备后期使用。当然了 web.xml 中还有一些其他的应用程序参数,最后都会一并配置到 StandardContext 中。
  • reconfigureStartStopExecutor() 用于重新配置启动和停止子容器的 Executor。默认是 1 个线程。我们可以配置 conf/server.xml 中 Engine 的 startStopThreads,来指定用于启动和停止子容器的线程数量,如果配置 0 的话会使用 Runtime.getRuntime().availableProcessors() 作为线程数,若配置为负数的话会使用 Runtime.getRuntime().availableProcessors() + 配置值,若和小与 1 的话,使用 1 作为线程数。当线程数是 1 时,使用 InlineExecutorService 它直接使用当前线程来执行启动停止操作,否则使用 ThreadPoolExecutor 来执行,其最大线程数为我们配置的值。
  • 需要注意的是 Host 的 init 操作是在 Start 阶段来做的, StardardHost 创建好后其 state 属性的默认值是 LifecycleState.NEW,所以在其调用 startInternal() 之前会进行一次初始化。

(编辑:三明站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读