Tomcat 是一个Web容器。作为 Web 应用的容器承载着 Web 请求处理和响应的工作

最开始用户通过浏览器查看诸如新闻之类的静态资源,此时就需要通过 HTTP 服务器向浏览器返回静态 HTML 资源,浏览器将解析的 HTML 呈现给使用者。这里的 Web 容器就是用来存放 HTTP 服务器,能够处理网络请求并且进行响应。

随着互联网的发展,用户需求从静态资源转向了动态资源的获取,同时浏览器在资源获取的同时还会与服务端进行一些交互。

由此 Web 容器的功能开始有了扩展,除了能够处理 HTTP 请求,还需要 HTTP 服务器调用服务端程序也就是常说的 Web 应用。

针对这种需求,Sun 公司推出了 Servlet 技术, Servlet 是运行在服务端的 Java 小程序。

由于 Servlet 不能独立运行,因此需要由一个 Servlet 容器来承载它,并且对其进行初始化启动等管理操作。

为了承载 Servlet,也加入了 Servlet 容器,不过每个 Servlet 都代表一个业务类,包含了一些业务应用如果都接入到 Web 容器中会用户提供统一的服务响应就需要遵循统一的接口。

说白了就是要遵守一定规则才能放到 Servlet 容器中,方便进行管理,那么这个规则就是 Servlet 接口。从图中可以看出 Servlet 接口会对单个的 Servlet 进行标准定义。

对于Tomcat而言,它并不知道我们会有什么样的方法,这些都只是在项目被部署进webapp下后才确定的,由此分析,必然用到了Java的反射来实现类的动态加载、实例化、获取方法、调用方法。但是我们部署到Tomcat的中的Web项目必须是按照规定好的Servlet 接口来进行编写,以便进行调用

public interface Servlet {public void init(ServletConfig config) throws ServletException;public ServletConfig getServletConfig();public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException;public String getServletInfo();public void destroy();
}

对于 Servlet 接口而言定义了 init 方法用做 Servlet 资源的初始化,同时也定义 destroy 方法用做 Servlet 资源的释放。

其中 Service 方法用来实现具体的业务需求,可以看到该方法传入 ServletRequest 和 ServletResponse 两个参数,分别表示封装了用户的请求信息和 Servlet 的响应信息。

接口中的 getServletConfig 方法会返回 ServletConfig,ServletConfig 是用来封装 Servlet 的初始化参数的,可以在 web.xml 配置 Servlet 参数,然后通过 getServletConfig 方法获取参数。

上面介绍了 Servlet 接口一下,再通过图 5 对 Servlet 接口调用的周边类进行深入了解。

如图 5 所示,Servlet 接口依赖 ServletConfig 接口,该接口正好是用来处理 Servlet 配置参数的,ServletConfig 接口同时也会关联 ServletContext 获取 Servlet 上下文的信息。

Servlet 接口中的 service 方法依赖两个参数分别是 ServletRequest 和 ServletResponse。

同时有两个接口 HttpServletRequest 和 HttpServletResponse 会分别继承 ServletRequest 和 ServletResponse。

一般而言 Servlet 作为接口需要具体的实现类去实现这个接口,因此 Servlet 规范提供了一个抽象类名叫 GenericServlet,它实现了 Servlet。

接着有一个 HttpServlet 的类继承 GenericServlet,为了处理 HTTP 请求这类也会依赖 HttpServletRequest 和 HttpServletResponse。

Servlet 接口定义是 Servlet 容器的重要组成部分,Servlet 容器通过接口去管理接入的 Servlet 实体。

在了解 Servlet 接口规范和 Servlet 容器以后,我们知道如果需要加载不同的动态资源(Web 应用)需要利用 Servlet 容器去加载对应的 Servlet,那么这个加载过程是如何进行的?

我们接下来看看 Servlet 的请求和响应流程。


如图 6 所示,这里通过 8 个步骤展示了 HTTP 请求和响应的流程:

1.用户通过浏览器发起 HTTP 请求。
2.Servlet 容器在接受到请求以后会对 HTTP 请求进行解析。
3.通过解析的结果以及配置信息创建 Servlet 实例。
4.实例创建以后调用 Servlet 实例的 init 方法完成实例初始化工作。
5.接下来就是调用 Servlet 中的 Service 方法完成具体业务。
6.Service 方法完成以后会将响应信息返回给 Servlet 容器。
7.Servlet 容器将 Servlet 返回的信息创建成 HTTP 响应返回给浏览器端。
8.最后容器关闭的时候,Servlet 容器调用 destroy 方法卸载掉 Servlet,并且释放对应的资源。

Tomcat的结构比较复杂,但是又比较模块化,所以只要我们找到了最核心的模块,对于tomcat的整体架构和工作原理就很好理解了。

Connector(连接器)组件负责生成请求对象和响应对象的,Tomcat默认为HttpConnector,负责根据收到的Http请求报文生成Request对象和Response对象,并把这两个对象传递给Container,然后根据Response中的内容生成相应的HTTP报文。

Container是容器的父接口,所有子容器都必须实现这个接口,简单来说就是服务器部署的项目是运行在Container中的。Container里面的项目获取到Connector传递过来对应的的Request对象和Response对象进行相应的操作。

Connector可以根据不同的的设计和应用场景进行替换,而一个Container可以对应多个Connector。多个Connector和一个Container就形成了一个Service,而Service可以对外提供服务。

而service由server提供生存环境并控制其生命周期,

假设有一个请求http://localhost:8080/test/index.jsp 我们梳理一下流程

1.请求先发送到本机端口8080,然后被在那里侦听的Coyote HTTP/1.1 Connector获得;
2. Connector把该请求交给它所在的Service的Engine来处理,并等待Engine的回应;
3.Engine获得请求localhost:8080/test/index.jsp,匹配它所有虚拟主机Host;
4.Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机);
5.localhost Host获得请求/test/index.jsp,匹配它所拥有的所有Context;
6.Host匹配到路径为/test的Context(如果匹配不到就把该请求交给路径名为"“的Context去处理);
7.path=”/test"的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet;
8.Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类;
9.构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法;
10.Context把执行完了之后的HttpServletResponse对象返回给Host;
11.Host把HttpServletResponse对象返回给Engine;
12.Engine把HttpServletResponse对象返回给Connector;
13.Connector把HttpServletResponse对象返回给客户browser;

上面我们知道了流程,但是connector是如何接受请求?又如何封装成Request和Response对象的呢?

Connector是使用ProtocolHandler来处理请求的,不同的ProtocolHandler代表不同的连接类型,比如我们之前说到的Http11Protocol使用的是普通Socket来连接的,Http11NioProtocol使用的是NioSocket来连接的

可以看到ProtocolHandler由包含了三个部件:Endpoint、Processor、Adapter

Endpoint用来处理底层Socket的网络连接,由于是处理底层的Socket网络连接,因此Endpoint是用来实现TCP/IP协议的,

Processor用于将Endpoint接收到的Socket封装成Request,用来实现HTTP协议的

Adapter用于将Request交给Container进行具体的处理,用来将请求适配到Servlet容器进行具体的处理

Endpoint的抽象实现类AbstractEndpoint里面定义的Acceptor和AsyncTimeout两个内部类和一个Handler接口。Acceptor用于监听请求,AsyncTimeout用于检查异步Request的超时,Handler用于处理接收到的Socket,在内部调用Processor进行处理。

到了这里,我们可以回答上面的问题了,但是Container是如何进行处理的以及处理完之后是如何将处理完的结果返回给Connector我们还不清楚,

Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine;

Host:代表一个站点,也可以叫虚拟主机,通过配置Host就可以添加站点;

Context:代表一个应用程序,对应着平时开发的一套程序,或者一个WEB-INF目录以及下面的web.xml文件;

Wrapper:每一Wrapper封装着一个Servlet的一个或多个实例;

Context和Host的区别是Context表示一个应用,Tomcat中默认配置下webapps下的每一个文件夹目录都是一个Context而整个webapps就是一个Host站点

我们访问应用Context的时候,

如果是Host(webapps)下的其他应用,则可以使用http://www.test.com/docs进行访问,

默认指定的根应用(ROOT)是可以进行改变的

Container如何处理请求

Container处理请求是使用Pipeline-Valve管道来处理的

Pipeline-Valve是责任链模式,责任链模式是指在一个请求处理的过程中有很多处理者依次对请求进行处理,每个处理者负责做自己相应的处理,处理完之后将处理后的请求返回,再让下一个处理着继续处理。

每个Pipeline都有特定的Valve,而且是在管道的最后一个执行,这个Valve叫做BaseValve,BaseValve是不可删除的;

在上层容器的管道的BaseValve中会调用下层容器的管道。

当执行到StandardWrapperValve的时候,会在StandardWrapperValve中创建FilterChain,并调用其doFilter方法来处理请求,这个FilterChain包含着我们配置的与请求相匹配的Filter和Servlet,其doFilter方法会依次调用所有的Filter的doFilter方法和Servlet的service方法,这样请求就得到了处理!

当所有的Pipeline-Valve都执行完之后,并且处理完了具体的请求,这个时候就可以将返回的结果交给Connector了,Connector在通过Socket的方式将结果返回给客户端。

如果执行过程中间出现问题就抛异常。

Tomcat的实现原理相关推荐

  1. Tomcat架构与原理

    Tomcat架构与原理 架构图 原理 ①.用户点击网页内容,请求被发送到本机端口8080,被在那里监听的Coyote HTTP/1.1 Connector获得. ②.Connector把该请求交给它所 ...

  2. 了解架构设计远远不够!一文拆解 Tomcat 高并发原理与性能调优

    来源 | 码哥字节 上帝视角拆解 Tomcat 架构设计,在了解整个组件设计思路之后.我们需要下凡深入了解每个组件的细节实现.从远到近,架构给人以宏观思维,细节展现饱满的美.关注「码哥字节」获取更多硬 ...

  3. Tomcat Servlet 工作原理

    文章目录 Tomcat Servlet 工作原理 Servlet Tomcat解析Context容器过程及如何构建Servlet Servlet容器启动过程 Web应用初始化工作 创建Servlet实 ...

  4. Tomcat长轮训原理解析

    长轮询 长轮询基于HTTP,用于数据更新的实时通知 广泛用于中间件配置实时同步通知如Apollo.Nacos 什么是长轮询 客户端向服务器请求,服务器接到请求后hold住连接,并等待数据返回(Java ...

  5. Tomcat集群同步原理

    #概述 随着C/S架构中,客户端对服务器的访问量及访问次数逐渐增多,单个服务器已经不能够满足客户端的请求了.于是现在大多数服务器都做成了集群的形式.而服务器集群会有一个很大问题,就是同步问题.比如,现 ...

  6. tomcat + spring mvc原理(二):tomcat容器初始化加载和启动

    tomcat + spring mvc原理(二):tomcat容器动态加载 容器通用生命周期标准 容器通用生命周期的实现 生命周期状态监听器的管理实现 生命周期方法实现 宏观来看各种容器生命周期的实际 ...

  7. tomcat + spring mvc 原理(一):tomcat原理综述和静态架构

    tomcat + spring mvc 原理(一):tomcat原理综述和静态架构 tomcat + spring mvc的运作模式 tomcat内部的基本容器构成 tomcat容器对应的外部配置 t ...

  8. tomcat + spring mvc原理(六):tomcat WAR包的部署与加载

    tomcat + spring mvc原理(六):tomcat WAR包的部署与加载 前言 监控的启动原理 状态监听 部署项目 前言 单独部署的tomcat服务器在运行中,当开发人员或者运维人员将开发 ...

  9. 操作系统:为什么IO操作不占用CPU却会导致进程阻塞?Web服务器每接收一个请求都会创建一个新的线程吗?Tomcat服务器工作原理?

    为什么IO操作不占用CPU却会导致进程阻塞?Web服务器每接收一个请求都会创建一个新的线程吗?这两个问题在我学操作系统以前我都挺困惑的.现在我来尝试着解答一下. 1. 为什么IO操作不占用CPU却会导 ...

  10. mysql性能调优与架构设计_了解架构设计远远不够!一文拆解 Tomcat 高并发原理与性能调优

    来源 | 码哥字节 上帝视角拆解 Tomcat 架构设计,在了解整个组件设计思路之后.我们需要下凡深入了解每个组件的细节实现.从远到近,架构给人以宏观思维,细节展现饱满的美.关注「码哥字节」获取更多硬 ...

最新文章

  1. 面试必备,Java线程状态之细节回顾
  2. 狂神说Java 之SpringBoot整合Shiro框架笔记!
  3. 阿里云天池大赛赛题解析――深度学习篇
  4. 3.4 多个例子中的向量化-深度学习-Stanford吴恩达教授
  5. 模块化加载_前端模块化简单总结
  6. access 微软以外 编辑_如何在 Microsoft Access 中修改查询属性
  7. 超级浏览器对跨境亚马逊防关联有用吗?
  8. [笔记]树的计数 Prufer序列+Cayley公式
  9. tf.contrib.silm学习
  10. 【NOIP普及组】1919:【02NOIP普及组】选数
  11. chrome模拟手机功能
  12. 2021高博会扩大举办,助力高尔夫运动新发展
  13. 一些linux常用操作(1)
  14. 2019世界顶级黑科技将在这里,跟大家见面
  15. Git workflow工作流及边角知识
  16. 03环信好友管理 - 添加好友(好友申请)
  17. 【强烈推荐】超详解Python-魔法函数(高级语法)
  18. autoit3 试用
  19. python实现发送和获取手机短信验证码
  20. 【硬件部署】RV1126开发板连接Windows常用工具ADB以及方法

热门文章

  1. 上班我是这样玩微信的,带你一起玩?
  2. 视觉SLAM十四讲学习笔记——ch9后端1
  3. 在谷歌云盘训练YOLOV5模型
  4. FileUtils(文件读写操作工具类)
  5. 乱码问题的原理及解决方法
  6. MathType公式编辑器的下载安装及导入Word
  7. 黑群晖linux删除文件夹命令,手把手教你黑群晖(二)
  8. 在线解方程软件集合(收藏)
  9. Uncaught RangeError: Maximum call stack size exceeded 超出最大调用值(个人解释)
  10. QFIL进入900E或90DB模式,download fail