设为首页 收藏本站
查看: 857|回复: 0

[经验分享] jetty_handler

[复制链接]

尚未签到

发表于 2017-2-25 11:54:25 | 显示全部楼层 |阅读模式
1.handler类图和时序
  先上一个handler的继承体系结构图

从上图可以看到,jetty通过一级一级的继承,不断的扩展handler的功能,从最简单的处理到复杂的web容器,下面一一分析之:

  然后再看一个简单的请求的handler调用过程:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24


at com.ali.b2b.crm.base.common.filter.LocaleFilter.doFilter(LocaleFilter.java:47)
at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1322)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:473)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:119)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:514)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:226)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:920)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:403)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:184)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:856)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:117)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:247)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:151)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:114)
at org.eclipse.jetty.server.Server.handle(Server.java:352)
at org.eclipse.jetty.server.HttpConnection.handleRequest(HttpConnection.java:596)
at org.eclipse.jetty.server.HttpConnection$RequestHandler.content(HttpConnection.java:1066)
at org.eclipse.jetty.http.HttpParser.parseNext(HttpParser.java:805)
at org.eclipse.jetty.http.HttpParser.parseAvailable(HttpParser.java:218)
at org.eclipse.jetty.server.HttpConnection.handle(HttpConnection.java:426)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint.handle(SelectChannelEndPoint.java:510)
at org.eclipse.jetty.io.nio.SelectChannelEndPoint$1.run(SelectChannelEndPoint.java:40)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:450)
at java.lang.Thread.run(Thread.java:619)



2.各种handler分析

2.1 handler接口


1


public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;


  参数解释:


  • target– request的目标, 为URI或者名字.
  • baseRequest–最原始的为包装的请求对象.最初server在处理的时候,
  • request–可能是最初的request,也可以是在处理过程中被包装过的request
  • response–可以是最初的或者被包装过的。
  在server解析完http头,构造好request和response传入第一个handler的时候,base quest和quest是一样的,参见server的handle方法:


1
2
3
4
5
6
7
8
9
10
11
12
13


public void handle(HttpConnection connection) throws IOException, ServletException
{
final String target=connection.getRequest().getPathInfo();
final Request request=connection.getRequest();
final Response response=connection.getResponse();
handle(target, request, request, response);
}
 
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
if (_handler!=null && isStarted())
_handler.handle(target,baseRequest, request, response);
}


  当然,handler继承了lifecycle接口,具有生命周期。

2.2 AbstractHandler
  一般要自己写handler都会继承于它,最主要就是持有了一个对于server的引用,同时提供了lifeCycle的最简实现。
  目前有3个直接继承于abstractHandler的最终实现是DefaultHandler,ResourceHandler和Redirector。

2.3 AbstractHandlerContainer
  该类继承自AbstractHandler,同时实现了HandlerContainer接口,并提供了对其的基本实现。主要有两种实现,一种是HandlerCollection,一种是HandlerWrapper。
HandlerCollection的逻辑如下:


1
2
3
4


for (int i=0;i<_handlers.length;i++)
{
_handlers[i].handle(target,baseRequest, request, response);



  它就是顺序的把所有的handler的handle方法执行一遍。
  HandlerWrapper的逻辑如下:


1
2
3
4
5
6
7


public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
if (_handler!=null && isStarted())
{
_handler.handle(target,baseRequest, request, response);
}
}


  通过装饰模式,可以嵌套地执行。两者的官方示意图如下:


2.4 ScopedHandler和Server
  HandlerWrapper有两个核心的子类,一个是Server,这个比较复杂,以后起专题再谈,
  一个是ScopedHandler,目前我的理解,它主要是
  For example if Scoped handlers A, B & C were chained together, then
the calling order would be:

A.handle(...)
A.doScope(...)
B.doScope(...)
C.doScope(...)
A.doHandle(...)
B.doHandle(...)
C.doHandle(...)



  If non scoped handler X was in the chained A, B, X & C, then the calling order would be:

A.handle(...)
A.doScope(...)
B.doScope(...)
C.doScope(...)
A.doHandle(...)
B.doHandle(...)
X.handle(...)
C.handle(...)
C.doHandle(...)




ScopedHandler有两个重要属性,一个是_outerScope,一个是_nextScope,outerScope是指一个handerWrapper链里的最外层的继承了ScopedHandler的handler,_nextScope是指下一个继承了ScopedHandler的handler,还有一个ThreadLocal的__outerScope是用了协助初始化的。
 
其具体的doScope和doHandle是通过如下代码来实现的:





1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18


    public final void nextScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException
{
if (_nextScope!=null)
_nextScope.doScope(target,baseRequest,request, response);
else if (_outerScope!=null)
_outerScope.doHandle(target,baseRequest,request, response);
else
doHandle(target,baseRequest,request, response);
}
 
public final void nextHandle(String target, final Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
if (_nextScope!=null && _nextScope==_handler)
_nextScope.doHandle(target,baseRequest,request, response);
else if (_handler!=null)
_handler.handle(target,baseRequest, request, response);
}


  ScopedHandler的目的主要是在一个链式的handler中,再实现多次的循环,或者说是一个handler事情做一半,然后由另一个handler做一半,再做剩下的这样的逻辑。ScopedHandler有3个子类,分别是contextHandler,ServletHandler和SessionHandler。基本上他们的doScope逻辑都是如果保存request的上下文,注入新的上下文,待处理完成后再还原以前的上下文,比如contextHandler的简化示例逻辑如下:


1
2
3
4
5
6
7
8


public void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
old_context=baseRequest.getContext();
if (old_context!=_scontext){
baseRequest.setContext(_scontext);
nextScope();
baseRequest.setContext(old_context);
}
}



2.5 ContextHandler
  顾名思义,是处理context的相关信息的。主要包括设置context,servletPath和classloader。
包含以下核心属性:
_baseResource:resource的根目录,用于ServletContext.getResource()等相关操作
_attributes:实现ServletContext的get和setAtrribute接口,管理context级别的属性信息。
_initParams:ServletContext级别的初始化参数,在web.xml中通过context-param设置,可以通过getServletContext().getInitParameter(“context/param”)得到
_contextListeners:在contextHandler的doStart时回调的listener
  比如一个使用例子:
web.xml配置如下:
  <context-param>
<param-name>myparam</param-name>
<param-value>1</param-value>
</context-param>
<listener>
<listener-class>MyServletContextListener</listener-class>
</listener>
  实现代码如下:


1
2
3
4
5
6


 
public class MyServletContextListener implements ServletContextListener{
public void contextInitialized(ServletContextEvent sce) {
String myparam = sce.getServletContext().getInitParameter("myparam");
}
}


  事实上在doStart代码的startContext中:


1
2
3
4
5
6
7
8
9


 
if (_contextListeners != null )
{
ServletContextEvent event= new ServletContextEvent(_scontext);
for (int i= 0; i < LazyList.size(_contextListeners); i++)
{
((ServletContextListener)LazyList.get(_contextListeners, i)).contextInitialized(event);
}
}



2.6 ServletHandler
  这个handler将不同的请求分派给不同的servlet,因此它持有所有web.xml下定义的filter和servlet的引用,以及对应的map关系。
在其doScope方法中,取得对应path的servletHolder:


1
2
3
4
5
6
7


 
if (target.startsWith("/")){
_servletPathMap.getMatch(pathInContext);
}else{
servlet_holder=(ServletHolder)_servletNameMap.get(target);
}
baseRequest.setUserIdentityScope(servlet_holder);


  在其doHandle方法中,取得fileterChain:


1
2
3
4
5
6
7
8


 
ServletHolder servlet_holder=(ServletHolder) baseRequest.getUserIdentityScope();
chain=getFilterChain(baseRequest, null,servlet_holder);
if (chain!=null){
chain.doFilter(req, res);
}else{
servlet_holder.handle(baseRequest,req,res);
}



2.7 SessionHandler
  SessionHandler主要是处理session相关事宜,他的核心属性有一个SessionManager


1
2
3
4
5
6
7
8
9
10
11
12
13


 
if (old_session_manager != _sessionManager)
{
// new session context
baseRequest.setSessionManager(_sessionManager);
baseRequest.setSession(null);
}
 
HttpSession session=null;
if (_sessionManager!=null)
{
session=baseRequest.getSession(false);
}


  这里主要是把_sessionManager set到baseRequest中,具体的每个request的session是在=baseRequest.getSession的时候new出来的。

2.8 ServletContextHandler
  Servlet Context, ContextHandler的子类,默认有sessionHandler,securityHandler和servletHandler3个元素,默认只有ServletHandler,但在构造函数中可以选择加上session和security的handler。在doStart的过程中,会创建并初始化3个元素handler,并将其构造成nest handler的链模式。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21


  protectedvoid startContext() throws Exception
    {
        // force creation of missing handlers.
        getSessionHandler();
        getSecurityHandler();
        getServletHandler();
 
        Handler handler = _servletHandler;
        if (_securityHandler!=null)
        {
            _securityHandler.setHandler(handler);
            handler=_securityHandler;
        }
        if (_sessionHandler!=null)
        {
            _sessionHandler.setHandler(handler);
            handler=_sessionHandler;
        }
        super.startContext();
        _servletHandler.initialize();
    }


  链的顺序就是session–>security–>servlet,可以空缺

2.9 WebAppContext
  ServletContextHandler的子类,后面起专题讲。

2.9 ContextHandlerCollection
  ContextHandlerCollection负责将不同context的请求对应给不同的handler,常规部署中经常是webappContext。
  ContextHandlerCollection在请求过程中以请求的最长匹配开始,逐步匹配直到找到合适的contextHandler。注意context的path是设置在各个contexthandler中的。比如我配置一个webAppContext,contextPath为”test”, 一个普通的ContextHandler,设置一个ResourceHandler到其中,contextPath为”test/res”,然后请求 localhost/test/res/a.htm,容器就会先到ResHandler的resourceBase下面去找a.htm,如果找不到,就交给webAppContext去处理。
简化后的代码如下:


1
2
3
4
5
6
7
8
9
10
11
12


Object contexts = map.getLazyMatches(target);
for (int i=0; i<LazyList.size(contexts); i++){
// then, match against the virtualhost of each context
Map.Entry entry = (Map.Entry)LazyList.get(contexts, i);
Object list = entry.getValue();
for (int j=0; j<LazyList.size(list); j++){
Handler handler = (Handler)LazyList.get(list,j);
handler.handle(target,baseRequest, request, response);
if (baseRequest.isHandled())
return;
}
}

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-347034-1-1.html 上篇帖子: jetty 架构 下篇帖子: Jetty Comet
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表