整体架构
我们想要了解一个框架, 首先要了解它是干什么的, Tomcat 我们都知道, 是用于处理连接过来的 Socket 请求的. 那么 Tomcat 就会有两个功能:
对外处理连接, 将收到的字节流转化为自己想要的 Request 和 Response 对象
对内处理 Servlet, 将对应的 Request 请求分发到相应的 Servlet 中
那么我们整体的骨架就出来了, Tomcat 其实就分为两大部分, 一部分是连接器 (Connnector) 处理对外连接和容器 (Container) 管理对内的 Servelet.
大体的关系图如下:
描述:
最外层的大框就是代表一个 Tomcat 服务, 一个 Tomcat 服务可以对应多个 Service. 每个 Service 都有连接器和容器.
这些对应的关系我们也可以打开在 Tomcat 目录配置文件中 server.xml 中看出来.
- <Server port="8006" shutdown="SHUTDOWN">
- <Service name ="Catalina">
- <Connector port ="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443"/>
- <Connector port="8010" protocol="AJP/1.3" redirectPort="8443"/>
- <Engine name="Catalina" defaultHost="localhost">
- <Realm className="org.apache.catalina.realm.LockOutRealm">
- <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
- </Realm>
- <Host name="localhost" appBase="webapps"></Host>
- </Engine>
- </Service>
- </Server>
- View Code
这里我们可以看到连接器其实就是 Connector, 一个 Service 中可以有多个连接器, 容器其实对应的就是 Engine.
Tomcat 的整体架构简单来说就是这样的对应关系. 接下来我们简单的介绍连接器的整体架构和容器的整体架构.
连接器
我们可以看到上图中连接器传给容器的是 ServletRequest 对象, 而容器传给连接器的是 ServletResponse 对象, 这些在网络传输过程中是肯定不行的, 因为网络传输中传送的字节流.
所以连接器的功能需求我们大概能总结出来以下几点.
Socket 连接
读取请求网络中的字节流
根据相应的协议 (Http/AJP) 解析字节流, 生成统一的 TomcatRequestt 对象
将 TomcatReques 传给容器
容器返回 TomcatResponse 对象
将 TomcatResponse 对象转换为字节流
将字节流返回给客户端
其实上面的细分都能总结为以下的三点
网络通信
应用层协议的解析
Tomcat 的 Request/Response 与
ServletRequest/ServletResponse
对象的转化
而在 Tomcat 中它也用了三个类来实现上面的三个功能, 分别对应如下
- EndPoint
- Processor
- Adapter
用图表示他们的关系的话就是这样
容器
容器, 顾名思义就是装东西的器具, 那么这个 Tomcat 容器是装什么的呢? 其实主要的就是装了 Servlet 的.
那么容器是如何设计的呢? Tomcat 的容器设计其实是用了组合设计模式(不了解组合设计模式的可以看我之前的文章不学无数 -- 组合模式).
其实从 Server.xml 中我们也能看到其关系了.
- <Engine name="Catalina" defaultHost="localhost">
- <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"></Host>
- </Engine>
- View Code
在这里面我们只能看到容器中的两个模块, 一个是顶层模块 Engine, 另一个是 Host,
其实还有两个模块:
一个是 Context 对应的是我们 webapp 里面的每个应用文件夹, 每个文件夹就是对应一个 Context,
还有一个模块 Wrapper 对应的是我们 Context 中的所有 servlet, Wrapper 管理了访问关系与具体的 Servlet 的对应. 图表示就是下面这样.
Tomcat 中容器所有模块都实现了 Container 接口, 而组合模式的意义就是使得用户对于单个对象和组合对象的使用具有一致性,
即无论添加多少个 Context 其使用就是为了找到其下面的 Servlet, 而无论添加多少个 Host 也是为了找个下面的 Servlet.
而在容器中设计了这么多的模块, 一个请求过来 Tomcat 如何找到对应的 Servlet 进行处理呢?
请求如何定位
我们就举个最简单的例子, 我们本机应用上启动了一个 Tomcat,webapp 下有我们部署的一个应用 buxuewushu.
我们在浏览器上输入 http://localhost:8080/buxuewushu/add.do 是如何找到对应 Servlet 进行处理呢?
在我们启动 Tomcat 的时候, 连接器就会进行初始化监听所配置的端口号, 这里我们配置的是 8080 端口对应的协议是 HTTP.
请求发送到本机的 8080 端口, 被在那里监听的 HTTP/1.1 的连接器 Connector 获得
连接器 Connector 将字节流转换为容器所需要的 ServletRequest 对象给同级 Service 下的容器模块 Engine 进行处理
Engine 获得地址
http://localhost:8080/buxuewushu/add
. 匹配他下面的 Host 主机
匹配到名为 localhost 的 Host(就算此时请求为具体的 ip, 没有配置相应的 Host, 也会交给名为 localhost 的 Host 进行处理, 因为他是默认的主机)
Host 匹配到路径为 /buxuewushu 的 Context, 即在 webapp 下面找到相应的文件夹
Context 匹配到 URL 规则为 *.do 的 servlet, 对应为某个 Servlet 类
调用其 doGet 或者 doPost 方法
Servlet 执行完以后将对象返回给 Context
Context 返回给 Host
Host 返回给 Engine
Engine 返回给连接器 Connector
连接器 Connector 将对象解析为字节流发送给客户端
Tomcat 系列(一)- 整体架构
来源: http://www.bubuko.com/infodetail-3343817.html