深入拆解 Tomcat & Jetty
李号双
eBay 技术主管
38890 人已学习
新⼈⾸单¥68
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
开篇词 (1讲)
深入拆解 Tomcat & Jetty
15
15
1.0x
00:00/00:00
登录|注册

29 | 比较:Jetty如何实现具有上下文信息的责任链?

doScope和doHandle方法
doStart方法
_outerScope和_nextScope变量
分享收获
消化和疑问
doStart方法的最后一步
ThreadLocal的使用
递归的重要性
doHandle方法
doScope方法
ServletContext
ScopedHandler的实现
初始化方法和请求处理方法的调用顺序
Jetty的实现方式
Tomcat的实现方式
课后思考
递归和线程私有数据
ContextHandler
Jetty的链式调用
责任链模式实现
Tomcat和Jetty的核心功能
Jetty责任链模式

该思维导图由 AI 生成,仅供参考

我们知道 Tomcat 和 Jetty 的核心功能是处理请求,并且请求的处理者不止一个,因此 Tomcat 和 Jetty 都实现了责任链模式,其中 Tomcat 是通过 Pipeline-Valve 来实现的,而 Jetty 是通过 HandlerWrapper 来实现的。HandlerWrapper 中保存了下一个 Handler 的引用,将各 Handler 组成一个链表,像下面这样:
WebAppContext -> SessionHandler -> SecurityHandler -> ServletHandler
这样链中的 Handler 从头到尾能被依次调用,除此之外,Jetty 还实现了“回溯”的链式调用,那就是从头到尾依次链式调用 Handler 的方法 A,完成后再回到头节点,再进行一次链式调用,只不过这一次调用另一个方法 B。你可能会问,一次链式调用不就够了吗,为什么还要回过头再调一次呢?这是因为一次请求到达时,Jetty 需要先调用各 Handler 的初始化方法,之后再调用各 Handler 的请求处理方法,并且初始化必须在请求处理之前完成。
而 Jetty 是通过 ScopedHandler 来做到这一点的,那 ScopedHandler 跟 HandlerWrapper 有什么关系呢?ScopedHandler 是 HandlerWrapper 的子类,我们还是通过一张图来回顾一下各种 Handler 的继承关系:
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

Jetty实现了具有上下文信息的责任链,通过HandlerWrapper实现了责任链模式,形成了一个链表。Jetty还实现了“回溯”的链式调用,即从头到尾依次链式调用Handler的方法A,完成后再回到头节点,再进行一次链式调用,调用另一个方法B。Jetty是通过ScopedHandler来实现这一点的,ScopedHandler是HandlerWrapper的子类,它引入了_outScope和_nextScope变量,用来控制doScope方法和doHandle方法的调用顺序。通过设置这些值,并在代码中判断这些值并采取相应的动作,ScopedHandler帮助搭建了调用框架,让Handler链上的doScope方法在doHandle、handle方法之前执行。这样Jetty的子类只需要实现doScope和doHandle方法,从而实现了具有上下文信息的责任链。ContextHandler是ScopedHandler的子类,实现了doScope和doHandle方法,维护了ServletContext和Web应用的初始化参数,完成了请求的修正、类加载器的设置,并调用nextScope。在doHandle方法里分别完成了相应的请求处理工作。Jetty中的ScopedHandler通过递归的方式来设置_outScope和_nextScope两个变量,然后通过判断这些值来控制调用的顺序。另外,ScopedHandler通过线程私有数据ThreadLocal来保存变量,既达到了传递变量的目的,又没有线程安全的问题。Jetty的doStart方法将线程私有变量__outerScope设置成null,以完成相应的操作。Jetty的实现原理涉及了递归和线程私有数据的使用,对于理解递归的精髓和线程安全有着重要意义。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《深入拆解 Tomcat & Jetty 》
新⼈⾸单¥68
立即购买
登录 后留言

全部留言(7)

  • 最新
  • 精选
  • neohope
    最后的问题,应该是这样的: protected void doStart() throws Exception { try{ _outerScope=__outerScope.get(); if (_outerScope==null){ //本次处理的第一个scope handler //告知后续scope handler,_outerScope选我 __outerScope.set(this); } super.doStart(); _nextScope= getChildHandlerByClass(ScopedHandler.class); } finally { if (_outerScope==null){ //本次处理结束 //为了下次同一个线程处理是, //还能正常的设置第一个scope handler //必须把threadlocal变量设为null __outerScope.set(null); } } } 此外,这一节里有一个non scoped handler X,一开始没太看懂调阅顺序。 后来发现是这样的: public final void nextHandle(String target...)... { if (_nextScope!=null && _nextScope==_handler){ //上面条件可以保证下一个handler是scope handler _nextScope.doHandle(target,baseRequest,request, response); } else if (_handler!=null){ //non scpoe handler调用下一个handler的 super.handle(target,baseRequest,request,response); } } 感觉类成员的命名不太合适, 比如__outerScope和_outerScope 比如_handler其实一直指向的是下一个handler,是不是该为_nextHandler更好一些?

    作者回复: 给你的钻研精神点赞👍

    2019-07-23
    9
  • despacito
    ScopedHandler 会有不同的实现类,而__outerScope 是ScopedHandler里static的变量,如果不设置为null,那么不同的子类实例执行doStrat()方法的时候,会有问题
    2019-07-16
    6
  • 帽子丨影
    感觉jetty的源码写的好混乱,经常没有注释,一个类也通常扩展3/4个接口功能,还各种循环嵌套。好难懂。。。
    2019-09-26
    5
  • 往事随风,顺其自然
    可以重新处理下一次请求
    2019-07-16
    3
  • nightmare
    每一次请求的请求链互不影响
    2019-07-16
    3
  • 绍棠
    threadlocal为什么在每次请求结束需要设置为null:为了下次请求复用。因为线程是用池化技术,下次请求优先共用线程,而不是新建线程
    2020-04-16
    1
  • Fredo
    1. 防止影响下个请求数据 2. 用完即清理,防内存泄露
    2024-02-06归属地:广东
收起评论
显示
设置
留言
7
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部