Tomcat底层原理

一、Tomcat启动时到底对我们的应用程序做了什么?

当我们把一个应用程序的war包放到Tomcat的webapps目录后,启动Tomcat,然后就可以通过浏览器发送Http请求访问该war包内的Servlet了。
这个过程包括:
1、启动Tomcat
2、Tomcat处理Http请求
而启动Tomcat的目的就是为了处理Http请求。

一个Http请求通常是这样子的:
http://localhost:8080/app/helloServlet
这个请求包括:

协议:http
主机名:localhost
端口:8080
应用名:app
Servlet名:helloServlet

我们通俗点来理解这个Http请求就是:浏览器通过Http协议,请求localhost:8080上的myapp应用内的helloServlet。

Tomcat架构俯视图:

在这里插入图片描述

二、那分析这个Http请求有什么用呢?和Tomcat有什么关系?

当然有关系,上面这个Http请求中的localhost:8080其实代表的就是Tomcat。我们一个应用程序想要从外部接收网络数据,那就要绑定一个端口,这个跟TCP协议有关系,外部请求发送给该端口,就能被对于的程序所接收到。Tomcat也是这样,所以,Tomcat默认绑定的就是8080。

所以上面这个Http请求首先是被Tomcat接收到,然后去解析这个请求。
解析这个请求包括:

请求所使用的方法,是GET,还是POST,还是其他
所请求的应用与Servlet的名字是什么
请求所携带的数据

当Tomcat把从8080端口获取的请求解析完成后,它就应该根据应用名和Servlet名字去找Servlet实现类了,只有找到Servlet实现类才能真正执行Servlet里面的doGet或doPost方法。

所以,这里又分两步:

根据请求中的应用名和Servlet名怎么找到对应的Servlet实现类呢
怎么执行Servlet实现类中跟请求对应的方法呢

首先关于第二点,很简单:可以用***反射***
那么对于第一点该怎么实现呢?
其实也很简单,要么默认,要么映射。
默认的意思就是,请求中的Servlet名就是类名,这种可行,但是不好用,一个类还有包名的,万一在一个应用中,存在不同的包下存在名字相同的Servlet,这个时候就尴尬了。
所以最好的方式就是映射,一个Servlet名对应一个Servlet实现类。这也就是为什么我们在定义Servlet时,一定要做一个mapping关系,不管是通过@WebServlet注解还是在web.xml中,都需要配置一个mapping才能被访问到。

所以,Tomcat通过监听端口,获取数据,然后解析数据,根据请求url找到对应的Servlet实现类,然后通过反射执行Servlet实现类中的方法

这个流程并不难,如果我们自己实现,30分钟内可能就能实现出来这么一个功能,这也是Tomcat的主线功能,那么Tomcat复杂在哪呢?
其实还是复杂在这条主线,这条主线再拆分一下就是两步:

获取并解析数据
寻找并执行Servlet

在这里插入图片描述

tomcat容器对比:
在这里插入图片描述

三、Servlet

我们在来细想一下这里的第二步:寻找并执行Servlet

我们通常说Tomcat是一个Servlet容器,到底体现在哪,怎么体现的呢?
我们得先来理解一下Servlet,Servlet=Server+Applet,表达的意思就是运行在服务端的应用程序,它跟运行在客户端的应用程序是相对的,运行在客户端的应用程序,可以随着用户的操作而发生变化,而运行在服务端的应用程序,用户是不能直接操作的,你只能通过发送网络请求来操作它,这就是Servlet的由来。这也就是为什么Servlet规范里会定义ServletRequest,ServletResponse接口,都是跟请求相关的,所以,Servlet其实就为Java程序员方便处理请求和响应的一种抽象,作为Java程序员,你只需要通过定义Servlet,然后接收到的ServletRequest对象就代表请求,而不用关心ServletRequest具体的实现类是什么,是谁实现的,都不用关系,只要知道这个对象代表一个请求即可。
所以谁来实现这些接口呢?大家自然就能想到了,是Tomcat、Jetty这些了。比如Tomcat中对应的请求实现类是RequestFacade,我们在Servlet中进行强制转化是没有问题的,比如这么写:

@Override

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    RequestFacade requestFacade = (RequestFacade) req;

    resp.getWriter().println("luban annotation servlet");

}

我们重新理解了Servlet之后,就可以再来理解Tomcat了,Tomcat确实是一个容器,但是是一个分层的容器。因为一个Servlet代表一个功能,一个应用中可以有多个Servlet,所以在Tomcat中存在Context容器,Context容器中收纳Servlet,Context就代表应用,也就是应用上下文,然后我们的应用是部署在主机上的,所以Tomcat中存在Host容器,一个Host容器中可以容纳多个Context容器,再继续,我们可能是多个主机所提供的功能属于同一范畴的,所以在Tomcat中,在Host之上还有一层Engine。所以我们说的容器包括:Engine、Host、Context。

而Tomcat除开实现了这个层级结构之外,还提供了一些辅助功能。
既然现在容器分层了,所以一个请求在寻找Servlet的过程中,就会经过每一层容器,那么每层容器在这个过程中都可以去做一些事情,并且允许用户自定义这些事情,比如可以在Host层去指定:所有请求该Host的请求都将日志打印到hostname.log文件中,或者所有请求该Host的请求都由该Host添加一下参数,其他容器也类似,这其实就是一种责任链模式,Tomcat中实现了这种模式,是通过:Pipeline和Valve实现的。

好,这是关于容器的分析。
接下来我们再来分析一下Tomcat是怎么解析请求的,上文我们分析了,Tomcat实际上就是把接收到的请求转化成RequestFacade对象,最后把这个对象传递给Servlet。
那么Tomcat的数据从哪来的呢?上文中我们一直默认Tomcat接收的是Http请求,那么这个Http请求是怎么到达Tomcat的呢?总不是凭空飞过来了的吧。
大家应该想到了,是通过网线传过来的,所以我们要分析Tomcat是怎么接收到Http请求,就要分析网络传输协议了。
首先,我们为什么需要网络传输协议呢?
网络是用来传输数据的,比如现在主机A有一份数据要发送给主机B,那么主机A在拥有数据的同时还是要知道主机B的地址,也就是IP,所以现在相当于主机A上要有:数据+对方IP地址

四、流程图

在这里插入图片描述

Tomcat:

(1)Tomcat中只有一个Server,一个Server可以有多个Service,一个Service可以有多个Connector和一个Container;
(2) Server掌管着整个Tomcat的生死大权;
(4)Service 是对外提供服务的;
(5)Connector用于接受请求并将请求封装成Request和Response来具体处理;
(6)Container用于封装和管理Servlet,以及具体处理request请求;

Connector:
在这里插入图片描述

四个子容器:

(1)Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine;
(2)Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点;
(3)Context:代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件;
(4)Wrapper:每一Wrapper封装着一个Servlet;

上述的包含关系或者说是父子关系,都可以在tomcat的conf目录下的server.xml配置文件中看出,下图是删除了注释内容之后的一个完整的server.xml配置文件(Tomcat版本为8.0)
在这里插入图片描述

更多详情

五、那么Tcp是用来干什么的呢?

回到上面的场景,主机A想把数据发送给主机B,那谁来保证数据能可靠的到达对方呢?这就是Tcp协议所要做的事情。
那Http协议又是怎么回事呢?我们上面接收的Ip,Tcp都是跟传输相关的,而Http是跟应用相关的,是跟数据所表达的意义相关的,比如,主机A发一份数据给主机B之后,主机B接收到这份数据后,它要干什么呢?它要执行什么动作呢?这就是Http协议所要表达的,通过在数据中增加一些有意义的元素,比如请求方法,这样数据接收方能更快的根据Http协议解析数据,完成对应的动作。
解析的比较粗,因为这不是本文的重点,我的重点是,那么谁来实现Http协议,谁来实现Tcp协议呢?
答案是:操作系统来实现Tcp协议,比如Linux、Windows,运行在操作系统之上的其他应用程序来实现Http协议,比如浏览器、Tomcat。
比如Linux的源码中就有关于Tcp协议的实现,包括三次握手,四次挥手,都是通过c语言来实现的。那么浏览器它依照Http协议定义好数据之后,怎么利用Tcp协议发送出去呢?Tomcat怎么利用Tcp协议接收数据呢?
浏览器能不能直接调用操作系统中实现TCP协议关于发送数据的函数呢?Tomcat能不能调用对应接收数据的函数呢?
原理上是可以的,但是就像我们开发业务一样,我们不会将真正实现业务的方法直接暴露给其他人调用,而会提供一个接口,操作系统也一样,这个接口就是Socket。
所以Tomcat是通过Socket从操作系统获取数据的,拿到数据后进行解析。
而Tomcat从操作系统系统拿数据又有几种方式,也就是IO模型:BIO,NIO,AIO,这些不同的模式Tomcat都是支持的,只需要在server.xml中进行配置即可。
简单记录了一下关于Tomcat的随笔,其实关于TSocket、IO模型可以写得更多一点,限于篇幅,本篇就到此为止吧,下次继续。

在这里插入图片描述

  • 10
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值