tomcat的原理-组件container

在 tomcat的原理-组件connector中,我们说CoyteAdapter类的sevice方法中 将request 和response 交给容器处理,那tomcat的container结构又是怎样的呢?

总述

先来张container的架构图:


image.png

1.container是一个接口, 它用于接收request 并返回response对象的一种容器
2.engine 是servlet引擎 ,是tomcat 容器中的顶级容器 ,管理多host。

  1. context 是servlet 的上下文,代表独立的应用程序。一个context可以有多个servlet。
  2. wrapper 是代表单独的servlet。
  3. tomcat中采用父子关系设计这些容器。为什么要这样设计?
    a.正好符合一个engine多host , 多 context ,多servlet 这种结构.
    b.分层架构,各司其职。
    c.组合模式 ,你中有我,我中有你。
  4. 最后我们用server.xml 来理解下tomcat 中的container关系:
image.png

分析

回顾上篇我们参数一个web请求访问tomcat会经过如下组件:

  1. accptor: 接收网络请求,发送事件给poller组件。
  2. poller: 接收I/O事件, 丢给业务线程池。
  3. processor: 处理socket。
  4. adapter :适配 httpServletReqeust 和 httpServletResponse
  5. 交给container 执行pipline。

来说说tomcat 的pipeline机制。
1.pipeline的结构?
本质就是个链表
初始状态: pipeline中用 两个属性 Valve first , Valve basic , first == null
初次添加 valve(假设叫a) : 给first 赋值 a 并将basic 连接到first后面
再次添加 valve(假设叫b): basic 连到b之后, b连接到basic 原来的前节点。

image.png

代码如下 : 类StandardPipeline 的addValve()

image.png

2.pipeline如何初始化的?
在container 实例化的时候,各个容器的pipeline完成初始化, 并设置基础的basic valve。
ContainerBase属性中:


image.png

StandardEngine类构造器中:


image.png

3.何时调用pipline?
在CoyoteAdapter类中的service方法中调用tomcat的pipline机制.


image.png

a. 由container的父子图我们知道,connector.getService().getContainer() 我们可以获取到 standardEngine对象
b. getFirst().invoke() 如果first == null , 直接调用basic valve 的invoke() ;否则 我们会在pipeline 的valve链上一直调用他的next valve 的invoke方法,直到最后一个basic valve 。
c. standardEngine 对象的pipleline属性的basic 为StandardEngineValve对象 , 会调用host 容器 的pipeline中的各个valve 直到 basicValve 。 过程和Engine容器的 pipeline一致。


image.png

image.png

d. 我们直接看StandardHostValve 的invoke() 方法 。


image.png

e.在看 StandardContextValve 的 invoke() 方法, 同 StandardHostValve 的invoke() 方法 ,同理调用Context容器中的每个valve。

image.png

在StandardContextValve 类中可以直接从request对象中获取到wrapper,我们思考一个问题 request.getWrapper()是如何将 wapper 封装到request对象中的??


image.png

结论: 在container的生命周期中,会使用发布订阅模式,发送事件,Mapper组件通过监听的方式去注册容器 , reqeust 对象在封装的时候从mapper 中匹配所需的容器对象装载到MappingData中,代码如下。

1.service中初始化mapper 和 mapperListner。


image.png
  1. mapperListner 实现了 ContainerListener, LifecycleListener接口


    image.png
  1. 在容器的生命周期方法中或添加子容器方法中会触发mapperListener 的containerEvent()或lifecycleEvent() ,会将容器注册到Mapper中
image.png
image.png
  1. 当tomcat 内部的request 在经过CoyteAdapter的service方法的时, 会调用Mapper的map方法将容器设置到request的MappingData中:


    image.png
image.png

f.context容器是如何添加子容器wrapper的?

我们知道wrapper 对应与我们web.xml 的servlet ,对于一个应用来说 我们可以配置很多servlet ,如果使用degister【后面分析tomcat lifecycle 再谈】 配置放入到context 中是不切实际的,
tomcat 通过发布订阅模式 监听器的方式来给context 配置子容器,上代码:

1.在StandardContext 的startInternal() 方法中, 会发送Lifecycle.CONFIGURE_START_EVENT 的事件


image.png
  1. ContextConfig 实现了LifecycleListener 接口,意味着当StandardContext 发送CONFIGURE_START_EVENT 事件后 ,ContextConfig会处理事件。


    image.png
  2. configureStart() 方法中调用了webconfig() 方法 , 在webConfig()方法中, 会扫描web.xml 文件 , WebXmlParser 解析文件, 加载ServletContainerInitializers , 配置context 的 过滤器FilterDef 等信息, 创建Wrapper 容器并添加到子容器中等操作
    ContextConfig 的webconfig()方法:


    image.png
image.png
image.png
image.png

这样context 就可以在start()生命周期方法中 , 去调用子容器wrapper 的start()方法了

总结:context 使用事件发送给contextConfig 配置context 属性/ 子容器等信息


image.png

g. 最后我们看下StandardWapperValve 的 invoke() 方法。


image.png

我们看下wrapper 是如何创建servlet的?

  1. 加载servlet


    image.png

实例工厂创建servlet 对象 , 其中servletClass 是contextConfig 解析web.xml 的时候set 到wrapper 中的。


image.png
  1. servlet 初始化 loadServlet方法中 调用了 initServlet(servlet)
image.png
image.png

为什么使用 门面模式 StandardWrapperFacade?
个人理解 :StandardWrapper 实现了servletConfig接口 ,StandardWrapperFacade 也实现了 servletConfig 接口,
但是StandardWrapper 中的很多wrapper 的细节 撸码者并不想暴露给servlet 所以使用 facade模式包装 StandardWrapper ,及只暴露servlet 所关心的。

到这里我们的servlet 已经创建好了, 在很久以前我开发中经常遇到乱码的问题 , 当时我记得写filter 来解决tomcat的乱码问题,在tomcat 中在调用我们的servlet 之前有一系列的filter , 下面我们看看tomcat 实现的Filter机制。

image.png

1.使用工厂模式创建拦截器链filterChain , 将web.xml中的配置的filter加入到filterChain的 filters 数组中 并 将n(filter数)自增1 , pos 用来记录当前执行的连接器下标。

  1. filterChain的doFilter()方法中: 当 n< pos 的时候 pos ++ , 并找到下一个filter【filter1】 继续执行 filter1 的dofilter()方法 , 再找 下下个filter【filter2】 继续执行 filter2 的dofilter()方法 ,依次类推 直到 n == pos

  2. 当 n== pos 的时候调用servlet的service方法处理业务

来回顾下责任链模式, 写个demo:

  1. 定义fiter 接口


    image.png
  2. 定义拦截链


    image.png
  1. 创建拦截器A B C 都实现了Filter 接口
image.png
image.png
  1. main 方法测试 :


    image.png
  2. 输出


    image.png

6.结论

image.png

总结

  1. tomcat 通过Adapter 的service 方法将 request 和response 交给 Engine Host Context wrapper 容器
  2. 每个容器中包含一个pipleLine ,而pipleLine 由多个valve 和一个标准BasicValue(StandardHostValve ...)
  3. Wrapper 容器的最后一个 Valve 会创建一个 Filter 链,并调用 doFilter() 方法,最终会调到 Servlet的 service方法。

来张图吧:

image.png

后面我们记录下tomcat 的生命周期和打破双亲委派机制 , 有错误的地方,请大佬指正。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,123评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,031评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,723评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,357评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,412评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,760评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,904评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,672评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,118评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,456评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,599评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,264评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,857评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,731评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,956评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,286评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,465评论 2 348

推荐阅读更多精彩内容