共计 2447 个字符,预计需要花费 7 分钟才能阅读完成。
导读 | 本文适合有基础的小伙伴,如果你对 tomcat 启动及请求的流程处理不熟悉,可能看起来会比较吃力。有兴趣了解的小伙伴可以参考我之前的博客,希望对你有帮助 |
浅谈 Tomcat 的启动流程(源码级别), 浅谈 Tomcat 接收到一个请求后在其内部的执行流程(源码).
整个准备工作,可以直接理解为一个模板方法模式。
直接启动 tomcat 时,使用到的 shell 脚本,该脚本是整个 tomcat 的启动入口;
tomcat 为了统一管理 tomcat 启动过程中相关组件的生命周期,使用了模板方法设计模式。该方法中包含了顶层的接口为 Lifecycle,以顶层接口中的 init 和 stop 方法为例,LifecycleBase 抽象类首先对 init 和 stop 方法进行一个基础的过滤,然后继续调用子类的 initInternal 和 stopInternal 方法。如果希望向 tomcat 中添加组件,就可以直接实现 LifecycleBase 抽象类,然后重写我们希望处理的生命周期的各个方法;
初始化需要使用的类加载器(tomcat 需要打破双亲委派机制,用来保证应用与应用之间的隔离性)
首先按照 catalina.java 类中配置的标签规则,解析 server.xml 类中各个标签的数据;然后根据前面的配置信息,初始化相关的组件对象,这里就包含了我们后文所需要的 Connector、ProtocolHandler、Pipeline 等对象;
我们实例化出来的一些组件对象,是用来处理请求的,这里就涉及相关后台线程的开启,该步骤的主要任务也主要就是开启对应的后台线程任务。
整个 tomcat 是一个大的 server 组件,每部署一个服务就是一个 service 组件。整个请求处理组件是基于组合模式,这里涉及了 ProtocolHandler、EndPoint、Processor。具体 ServletRequest 对象数据的转发涉及到适配器模式,这里涉及 Container、Adapter
在 tomcat 启动阶段,会根据 server.xml 中如下的标签,选择初始化何种的 Connector 对象,即完成对 protocolHandlerClassName 参数的赋值,后期利用反射初始化 ProtocolHandler 对象
内部含有 EndPoint+Processor 的组合操作。分别用于解决什么网络 IO 模型(NIO、APR、JIO),什么应用层协议(HTTP、AJP)。这里就是组合模式的体现
用于通信监听的接口,是具体的 Socket 接收和发送处理器,是对传输层的抽象。每一个 EndPoint 类中都有一个 Acceptor 类,用来接收外部发来的请求。
Processor 用来实现 HTTP/AJP 协议,是对应用层的抽象。Processor 接收来自 EndPoint 的 Socket,读取字节流解析成 Tomcat Request 和 Response 对象,并通过 Adapter 将其提交到容器处理
紧接上文,Adapter 接收由 ProtocolHandler 组件处理后的 ServletRequest,但由于协议不同,客户端发过来的请求信息也不尽相同,但我们编写的具体的业务代码中的 ServletRequest 是一个标准的对象。Tomcat 的解决办法为使用适配器模式、门面模式,通过 CoyoteAdapter 类的 service 方法,将非标准的 ServletRequest 对象(org.apache.coyote.ServletRequest)适配为 ServletRequest 对象(org.apache.catalina.connector),但真正的传递给业务层面的 ServletRequest 是经过 tomcat 门面模式处理后符合 servlet 规范的 ServletRequest 对象(javax.servlet.ServletRequest)
用来装载东西的容器,在 Tomcat 里,容器就是用来装载 Servlet 的。Tomcat 通过一种分层的架构,使得 Servlet 容器具有很好的灵活性。Tomcat 设计了 4 种容器,分别是 Engine、Host、Context 和 Wrapper。这 4 种容器不是平行关系,而是父子关系。** 该部分对象的初始化也是在 tomcat 启动阶段完成的,这里将所有的组件以内部 next 属性嵌套的关系完成调用。** 这里的四个对象虽然属于父子关系,但是他们的实现方式都是基于一个 ValveBase 抽象类的模板方法,使用内部的 next 属性完成父子关系的构建。
- Engine:引擎,Servlet 的顶层容器,用来管理多个虚拟站点,一个 Service 最多只能有一个 Engine;
- Host:虚拟主机,负责 web 应用的部署和 Context 的创建。可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可以部署多个 Web 应用程序;
- Context:Web 应用上下文,包含多个 Wrapper,负责 web 配置的解析、管理所有的 Web 资源。一个 Context 对应一个 Web 应用程序;
- Wrapper:表示一个 Servlet,最底层的容器,是对 Servlet 的封装,负责 Servlet 实例的创建、执行和销毁。
// 指定 service 中的,指定 container 中的,指定的 pipeline 中的,第一个需要处理的 ValveBase 请求过滤实现类
xxx.getService().getContainer().getPipeline().getFirst().invoke(request, response)