jetty_handler

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;
                }
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值