简述Tomcat的本质

 

Tomcat是非常流行的Web Server,它还是一个满足Servlet规范的容器。那么想一想,Tomcat和我们的Web应用是什么关系?

从感性上来说,我们一般需要把Web应用打成WAR包部署到Tomcat中,在我们的Web应用中,我们要指明URL被哪个类的哪个方法所处理(不论是原始的Servlet开发,还是现在流行的Spring MVC都必须指明)。

由于我们的Web应用是运行在Tomcat中,那么显然,请求必定是先到达Tomcat的。Tomcat对于请求实际上会进行下面的处理:

第一:提供Socket服务

Tomcat的启动,必然是Socket服务,只不过它支持HTTP协议而已!

这里其实可以扩展思考下,Tomcat既然是基于Socket,那么是基于BIO or NIO or AIO呢?

第二:进行请求的分发

要知道一个Tomcat可以为多个Web应用提供服务,那么很显然,Tomcat可以把URL下发到不同的Web应用。

第三:需要把请求和响应封装成request/response

我们在Web应用这一层,可从来没有封装过request/response的,我们都是直接使用的,这就是因为Tomcat已经为你做好了!

Tomcat的处理流程:把URL对应处理的Servlet关系形成,解析HTTP协议,封装请求/响应对象,利用反射实例化具体的Servlet进行处理即可。【Tomcat启动后,在接收到某个请求后,就可以根据请求路径和url-pattern进行匹配,如果匹配成功,则会把这个请求交给对应的servlet进行处理。】

处理流程简述:

  1. 浏览器在请求一个Servlet时,会按照HTTP协议构造一个HTTP请求,通过Socket连接发送给Tomcat
  2. Tomcat通过不同的IO模型都可以接收到Socket的字节流数据
  3. 接收到数据后,按HTTP协议解析字节流,得到HttpServletRequest对象
  4. 再通过HttpServletRequest对象,也就是请求信息,找到该请求对应的Host、Context、Wrapper
  5. 然后将请求交给Engine层处理
  6. Engine层处理完,就会将请求交给Host层处理
  7. Host层处理完,就会将请求交给Context层处理
  8. Context层处理完,就会将请求交给Wrapper层处理
  9. Wrapper层在拿到一个请求后,就会生成一个请求所要访问的Servlet实例对象
  10. 调用Servlet实例对象的service()方法,并把HttpServletRequest对象当做入参
  11. 从而就调用到Servlet所定义的逻辑

问题一:

Tomcat是如何根据HTTP协议来解析字节流的。

获取字节流

Tomcat底层是通过TCP协议,也就是Socket来获取网络数据的,那么从Socket上获取数据,就涉及到IO模型,在Tomcat8以后,就同时支持了NIO和BIO。

在Tomcat中,有一个组件叫做Connector,他就是专门用来接收Socket连接的,在Connector内部有一个组件叫ProtocolHandler,它有好几种实现:
Http11Protocol
Http11NioProtocol
Http11AprProtocol

解析字节流

不同的IO模型只是表示从Socket上获取字节流的方式不同而已,而获取到字节流之后,就需要进行解析了,之前我们说过,Tomcat需要按照HTTP协议的格式来解析字节流,下面是HTTP协议的格式:

 

 

所以,浏览器或者HttpClient在发送数据时,同样需要按照Http协议来构造数据(字符串),然后将字符串转成字节发送出去,所以Tomcat解析字节流的逻辑就是:

从获得的第一个字节开始,遍历每个字节,当遇到空格时,那么之前所遍历到的字节数据就是请求方法

然后继续遍历每个字节,当遇到空格时,那么之前遍历到的字节数据就是URL

然后继续遍历每个字节,当遇到回车、换行符时,那么之前遍历到的字节数据就是协议版本,并且表示请求行遍历结束

然后继续遍历当遇到一个回车符和换行符时,那么所遍历的数据就是一个请求头

继续遍历当遍历到两个回车符和换行符时,那么所遍历的数据就是一个请求头,并且表示请求头全部遍历完毕

剩下的字节流数据就表示请求体

值得注意的是,如果使用的是长连接,那么就有可能多个HTTP请求共用一个Socket连接,那么Tomcat在获取并解析Socket连接中的字节流时,该如何判断某个HTTP请求的数据在哪个位置结束了呢?也就是如何判断一个请求的请求体何时结束?

有两种方式:

  1. 设置Content-Length:在发送请求时直接设置请求体的长度,那么Tomcat在解析时,自然就知道了当前请求的请求体在哪个字节结束

  2. 设置Transfer-Encoding为chunk:也就是分块传输,在发送请求时,按如下格式来传输请求体,[chunk
    size][\r\n][chunk data][\r\n][chunk size][\r\n][chunk
    data][\r\n][chunk size = 0][\r\n][\r\n],注意最后的chunk
    size=0和两个回车换行符,只要Tomcat解析到这些时,就表示接收到了最后一块,也就表示请求体结束了

问题二

在Tomcat中存在四大Servlet容器:

  • Engine:直接理解为一个Tomcat即可,一个Tomcat一个Engine

  • Host:一个Host表示一个虚拟服务器,可以给每个Host配置一个域名

  • Context:一个Context就是一个应用,一个项目

  • Wrapper:一个Wrapper表示一个Servlet的包装,Wrapper在后文详解

并且这四个Servlet容器是具有层次关系的:一个Engine下可以有多个Host,一个Host下可以有多个Context,一个Context下可以有多个Wrapper,一个Wrapper下可以有多个Servlet实例对象。

Tomcat接收到某个请求后,首先会判断该请求的域名,根据域名找到对应的Host对象,Host对象再根据请求信息找到请求所要访问的应用,也就是找到一个Context对象,Context对象拿到请求后,会根据请求信息找到对应的Servlet,那么Wrapper是什么?

我们定义的某个Servlet,在Tomcat中可能会存在多个该类型的实例对象,所以Tomcat需要再抽象出来一层,这一层就是Wrapper,一个Wrapper对应一个Servlet类型,Wrapper中有一个集合,用来存储该Wrapper对应的Servlet类型的实例对象。

四大容器的作用:

Engine:可以处理Tomcat所接收到所有请求,不管这些请求是请求哪个应用或哪个Servlet的。

Host:可以处理某个特定域名的所有请求

Context:可以处理某个应用的所有请求

Wrapper:可以处理某个Servlet的所有请求

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值