首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 开源软件 >

jetty源码分析二-handlers

2013-11-08 
jetty源码分析2-handlers1.handler类图和时序先上一个handler的继承体系结构图从上图可以看到,jetty通过一

jetty源码分析2-handlers
1.handler类图和时序

先上一个handler的继承体系结构图


jetty源码分析二-handlers

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

?

在分析之前,再看一个简单的请求的handler调用过程:

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)

?可以看到,在一个请求的过程中,各个一般也是多个handler组合使用的。

?

2.handler继承体系分析2.1 handler接口
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException

?


参数解释:

target– request的目标, 为URI或者名字.baseRequest–最原始的为包装的请求对象.最初server在处理的时候,request–可能是最初的request,也可以是在处理过程中被包装过的requestresponse–可以是最初的或者被包装过的。


在server解析完http头,构造好request和response传入第一个handler的时候,base quest和quest是一样的,参见server的handle方法:

  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);    }

?

上面源码的第一个handle方法,是在解析完http头之后,由parser回调httpconnection的接口,然后再调用sever的这个handle方法,这个是所有请求进入handler体系的入口。而下面这个方法,是server作为一个handler实现的handler接口。当然,handler继承了lifecycle接口,具有和server相同的生命周期。

2.2 AbstractHandler

??? 一般要自己写handler都会继承于它,AbstractHandler最主要就是持有了一个对于server的引用,同时提供了lifeCycle的最简实现。

目前除了AbstractHandlerContainer外,还有有3个直接继承于abstractHandler的最终实现是DefaultHandler,ResourceHandler和Redirector,看名字大家应该都能猜到这3个handler的作用了。

2.3 AbstractHandlerContainer

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

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


它就是顺序的把所有的handler的handle方法执行一遍。

HandlerWrapper的逻辑如下:

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


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

jetty源码分析二-handlers

2.4 ScopedHandler和Server

HandlerWrapper有两个核心的子类,一个是Server,这个比较复杂,以后起专题再谈。

另一个是ScopedHandler,它主要是完成一个handler链的两次循环调用。官方解释是这样的:

?

For example if Scoped handlers A, B & C were chained together, then
the calling order would be:

public final void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { if (_outerScope==null) doScope(target,baseRequest,request, response); else doHandle(target,baseRequest,request, response); } 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); } <context-param><param-name>myparam</param-name><param-value>1</param-value></context-param><listener><listener-class>MyServletContextListener</listener-class></listener>

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

?

事实上是通过ContextHandler的doStart代码的startContext中去调用的

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

?

基本上ContextHandler的doScope逻辑是如果保存request的上下文,注入新的上下文,待处理完成后再还原以前的上下文,比如contextHandler的简化示例逻辑如下:

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

??这种情况貌似比较少,从一个contexthandler派发到另外一个contexthandler,开始怀疑是requestDispatcher的情况,后来看代码发现requestDispatcher只做同一个context内部的转发(参考:http://vinfai.iteye.com/blog/483886),现在怀疑是continuation可能会造成,但未验证。

2.6?ServletHandler

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

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

?

在其doHandle方法中,取得fileterChain:

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

  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的链模式。

  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去处理。
简化后的代码如下:

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;                } } 

?

热点排行