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