第1节-深入理解Tomcat
简介
tomcat是一个web服务器,运行jsp和servlet,使用HTTP与客户端(通常是浏览器)进行通信。
构成
下图是tomcat的架构,可以看出:核心内容是Connector和Container组件。
一个Server服务器中可能有多个Service,Service可以暂时理解为“服务”。Server负责管理Service的生命周期,让外界能够访问。
Service将Connector和Container联系在一起了,类似“一纸婚约”,将一对夫妻结合,组成一个家庭。
下面就看一下核心内容部分吧
1、Connector
在学Java web基础的时候,提到过当从浏览器传过来http请求之后,web容器会创建一个request和response对象。在Tomcat中,负责该创建工作的是Connector组件。
Connector连接器可以有一个或多个,默认情况下会开启两个HTTP协议和AJP协议。
2、Container
先来看一下Container的详细结构图:
Container容器有四个子容器:Engine、Host、Context和Wrapper,他们之间是父子包含关系。
1)、Engine
2)、Host(虚拟主机)
3)、Context(所属的web应用上下文)
4)、Wrapper(针对的是每个具体的servlet,可以说他是最直接和servlet打交道的。)
可以看一下Tomcat的server.xml文件,来深入了解各组件之间的关系。
<?xml version="1.0" encoding="UTF-8"?>
<!--Server-->
<Server port="8005" shutdown="SHUTDOWN">
<Service name="Catalina">
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html (blocking & non-blocking)
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL HTTP/1.1 Connector on port 8080
-->
<Connector URIEncoding="GB18030" connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443"/>
<!-- A "Connector" using the shared thread pool-->
<!--
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
<!-- Define a SSL HTTP/1.1 Connector on port 8443
This connector uses the JSSE configuration, when using APR, the
connector should be using the OpenSSL style configuration
described in the APR documentation -->
<!--
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
maxThreads="150" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" />
-->
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/>
<!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
analyzes the HTTP headers included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html -->
<Engine defaultHost="localhost" name="Catalina">
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log." suffix=".txt"/>
<Context docBase="shop" path="/shop" reloadable="true" source="org.eclipse.jst.jee.server:shop"/></Host>
</Engine>
</Service>
</Server>
设计思想
1)职责链模式
设计Container时使用到了职责链模式,我们可以明显的看到,Engine、host、context和Wrapper连接成一个链。当请求到来时,通过该链传递,最终到达处理请求的子容器。大话中的例子是“请假审批”,员工请假流程是一层一层进行的,如果经理可以审批,就不再继续走流程。如果经理无权力审批,就往上一层总经理传送,总经理可以审批就审批,不可以审批,请求就继续走下去,直到有人处理或请求被撤销。
多个对象有机会处理请求,发出请求和处理请求两者之间耦合关系减弱。对象连成一条链,沿着该链传递请求,直到有对象处理它为止。
2)命令模式
在设计Connector和Container关系时用到了命令模式。
Tomcat中可以有多个Connector,多个Connector和一个Container来构成了一个Service。Connector是请求者,而Container是接受命令并且执行的人。类似大话设计模式中,顾客点餐成烤串的例子。
将请求封装成一个对象,我们可以用参数封装各种请求,并且进行请求排队完成及时撤销等功能。
3)观察者模式
这个模式是比较常用的了,含义也就不用多说了,经常被用来实现“异步处理”。在Tomcat中有很多地方都用到了该模式,比如:Servlet实力的创建、Session管理、Lifecycle等。
观察者模式,也叫事件监听机制,也叫发布-订阅模式。想到什么?JMS的实现异步消息处理的Pub-Sub消息模型,还有NIO中将多个Channel注册到selector中监听消息等等等等。
大话中的例子是“老板回来,我不知道”。
Servlet初始化
执行service方法
在分析Wrapper方法中提到,StandardWrapper会调用allocate方法从实例池栈中弹出一个Servlet处理请求,这个Servlet实例在完成初始化后,并经过一系列过滤器的过滤后就到达Servlet实例的service方法,这个过程就是过滤器执行的过程。这样Servlet实例就顺利调用到了service方法,之后发生的过程就是我们熟悉的request获取参数并用response进行响应的过程了。
http://localhost:8080/examples/composite.jsp的处理过程:
- 在端口8080启动Server,并通知Service完成启动,Service通知Connector完成初始化和启动的过程
- Connector首先收到这个请求,会调用ProtocolHandler完成http协议的解析,然后交给SocketProcessor处理,解析请求头,再交给CoyoteAdapter解析请求行和请求体,并把解析信息封装到Request和Response对象中
- 把请求(此时应该是Request对象,这里的Request对象已经封装了Http请求的信息)交给Container容器
- Container容器交给其子容器——Engine容器,并等待Engine容器的处理结果
- Engine容器匹配其所有的虚拟主机,这里匹配到Host
- 请求被移交给hostname为localhost的Host容器,host匹配其所有子容器Context,这里找到contextPath为/examples的Context容器。如果匹配不到就把该请求交给路径名为”“的Context去处理
- 请求再次被移交给Context容器,Context继续匹配其子容器Wrapper,由Wrapper容器加载composite.jsp对应的servlet,这里编译的servlet是basic_002dcomparisons_jsp.class文件
- Context容器根据后缀匹配原则*.jsp找到composite.jsp编译的java类的class文件
- Connector构建一个org.apache.catalina.connector.Request以及org.apache.catalina.connector.Response对象,使用反射调用Servelt的service方法
- Context容器把封装了响应消息的Response对象返回给Host容器
- Host容器把Response返回给Engine容器
- Engine容器返回给Connector
- Connetor容器把Response返回给浏览器
- 浏览器解析Response报文
- 显示资源内容
根据前面的内容,其中的映射关系是由MapperListener类完成的。
推荐阅读
-
《深入理解Java虚拟机》-----第13章 线程安全与锁优化
-
《深入理解Java虚拟机》-----第10章 程序编译与代码优化-早期(编译期)优化
-
《深入理解 C# (第2版)》 - 学习笔记
-
《深入理解Java虚拟机》-----第12章 Java内存模型与线程
-
深入理解 Tomcat(五)源码剖析Tomcat 启动过程----类加载过程
-
深入理解Spring Cloud与微服务构建 第2版 方志朋 著 人民邮电出版社
-
深入理解Java虚拟机读书笔记之:第6章 Java class文件
-
深入理解Java虚拟机读书笔记之:第2章 平台无关
-
深入理解Java虚拟机读书笔记之:第3章 安全(1)
-
深入理解Java虚拟机读书笔记之:第3章 安全(2)