ScopedHandler在Jetty的Handler体系中属于比较重要的一个成员,像ContextHandler、SessionHandler、ServletHandler、WebappContext等重要组件都直接或间接的继承了ScopedHandler,所以在学习其它更具体handler之前,先来分析下它的源码。先来看下ScopedHandler的类图:
从类图中可以看到继承的层次比较深,所以还是从父类开始分析,LifeCycle接口和AbstractHandler前面已经分析过,就不再次分析了。
1.HandlerContainer和AbstractHandlerContainer
HandlerContainer是一个接口,它的定义是一个包含其它Handlers的Handler。也就是本身是一个handler但又可以看成是可以持有其它handler的Handler容器,接口的源码比较简单,四个方法的含义都比较容易理解:
/**
* A Handler that contains other Handlers.
* <p>
* The contained handlers may be one (see @{link {@link org.eclipse.jetty.server.handler.HandlerWrapper})
* or many (see {@link org.eclipse.jetty.server.handler.HandlerList} or {@link org.eclipse.jetty.server.handler.HandlerCollection}.
*
*/
public interface HandlerContainer extends LifeCycle
{
//以数组形式返回含有的handlers
public Handler[] getHandlers();
//以数组形式返回含有的handler以及这些handler的子Handler
public Handler[] getChildHandlers();
//以数组形式返回ChildHandlers中类型为byclass类型的Handler
public Handler[] getChildHandlersByClass(Class<?> byclass);
//返回ChildHandlers中第一个类型为byclass的Handler
public <T extends Handler> T getChildHandlerByClass(Class<T> byclass);
}
从类图上就可以看到AbstractHandlerContainer实现了HandleContainer并且继承了AbstractHandler,上面说到HandlerContainer的定义是既是一个Handler又是Handler容器,但因为它没有实现Handler接口所以并不能算是一个Handler,所以只有AbstractHandlerContainer才完全符合上面的定义,它事实上也是所有HandlerContainer子类的父类。
AbstractHandlerContainer实现了HandlerContainer接口中的后三个方法,getHandlers()方法留给了子类去实现。源码如下:
public Handler[] getChildHandlers()
{
Object list = expandChildren(null,null);
return (Handler[])LazyList.toArray(list, Handler.class);
}
/* ------------------------------------------------------------ */
public Handler[] getChildHandlersByClass(Class<?> byclass)
{
Object list = expandChildren(null,byclass);
return (Handler[])LazyList.toArray(list, byclass);
}
/* ------------------------------------------------------------ */
public <T extends Handler> T getChildHandlerByClass(Class<T> byclass)
{
// TODO this can be more efficient?
Object list = expandChildren(null,byclass);
if (list==null)
return null;
return (T)LazyList.get(list, 0);
}
可以看到都是借助expandChildren()方法来实现的,expandChildren()方法的目的是获取当前handler持有的所有handler对象及这些对象持有的子handler对象,将其加入到传入的list中去,如果传入了byClass参数则只选择那些和byClass类型相符的handler加入。但是这里其实还没有提供一个可以直接使用的实现,需要具体的子类去重写这个方法:
protected Object expandChildren(Object list, Class<?> byClass)
{
return list;
}
另外还提供了一个expandHandler方法,来将制定Handler展开,并加入到传入的list中,这个方法在当前类中没有使用到,但是在子类中是用到了的。
protected Object expandHandler(Handler handler, Object list, Class<Handler> byClass)
{
if (handler==null)
return list;
if (byClass==null || byClass.isAssignableFrom(handler.getClass()))
list=LazyList.add(list, handler);
if (handler instanceof AbstractHandlerContainer)
list=((AbstractHandlerContainer)handler).expandChildren(list, byClass);
else if (handler instanceof HandlerContainer)
{
HandlerContainer container = (HandlerContainer)handler;
Handler[] handlers=byClass==null?container.getChildHandlers():container.getChildHandlersByClass(byClass);
list=LazyList.addArray(list, handlers);
}
return list;
}
至此AbstractHandlerContainer和HandlerContainer就分析完了,值得注意的是虽然AbstractHandlerContainer声称是一个Container,但是确没有定义任何用于存储Handler的容器,甚至没有提供addHandler()之类的方法;实际上这一部分都是在具体子类里实现的,所以AbstractHandlerContainer中定义的方法是不多的。
2.HandlerWrapper
HandlerWrapper正如其名字所表示的是一个包装类,它里面持有一个protected Handler _handler 的属性就是其代理的Handler对象,并为这个属性提供了get()和set()方法:
//获取当前HandlerWrapper包装的Handler对象
public Handler getHandler(){
return _handler;
}
//设置当前HandlerWrapper的包装Handler对象,注意里面有对server引用的一些更新操作
public void setHandler(Handler handler) {
if (isStarted()) {
throw new IllegalStateException(STARTED);
}
Handler old_handler = _handler;
_handler = handler;
if (handler != null) {//设置当前管理的server对象
handler.setServer(getServer());
}
if (getServer() != null) {//更新server对象中的引用
getServer().getContainer().update(this, old_handler, handler, "handler");
}
}
HandlerWrapper的生命周期方法doStart()、doStop(),处理请求的方法handle()等都是直接调用的_handler相应的方法,简单的进行转发没有自己的处理逻辑(在一些子类里是添加了一些逻辑的)。
/*
* @see org.eclipse.thread.AbstractLifeCycle#doStart()
*/
@Override
protected void doStart() throws Exception {
if (_handler != null) {
_handler.start();
}
super.doStart();
}
/*
* @see org.eclipse.thread.AbstractLifeCycle#doStop()
*/
@Override
protected void doStop() throws Exception {
if (_handler != null) {
_handler.stop();
}
super.doStop();
}
public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {
if (_handler != null && isStarted()) {
_handler.handle(target, baseRequest, request, response);
}
}
从继承关系上可以看到HandlerWrapper还是一个HandlerContainer,这个容器中持有的唯一Handler对象就是被包装的_handler对象,下面是重写的getHandlers()方法:
public Handler[] getHandlers()
{
if (_handler==null)
return new Handler[0];
return new Handler[] {_handler};
}
HandlerWrapper中还重写了expandChildren()方法,将持有的_handler对象传给expandHandler()来进行处理来获取容器中存放的所有handler。
@Override
protected Object expandChildren(Object list, Class byClass) {
return expandHandler(_handler, list, byClass);
}
这样重载之后调用getChildHandlerByClass()方法返回的就是_handler对象了,这一点很重要在ScopeHandler中的doScope()方法中需要用到这个方法。
在Jetty中HandlerWrapper一个很重要的作用就是形成Handler链,所谓的Handler链就是指几个Handler组合成链式结构,对第一个handler调用handle()方法后整条链上的各个handler的handle()都会被依次调用。如下面的代码所示:
//handlerA handlerB都是HandlerWrapper类型,handlerC是普通Handler类型
HandlerWrapper handlerA;
HandlerWrapper handlerB;
Handler handlerC;
//组合成handler链
handlerA.setHandler(handlerB);
handlerB.setHandler(handlerC);
handlerA.handle();
//调用顺序: handlerA.handle()--->handlerB.handle()--->handlerC.handle();
根据上面HandlerWrapper的handle()方法,这种行为其实很好理解。形成这种handler链的好处在于可以方便请求的处理,比如实际中WebAppContext–>SessionHandler—>SecurityHandler—>ServletHandler形成了handler链,那么将请求交给WebAppContext之后,就可以经过不同的Handler处理最后交给ServletHandler从而交给应用程序处理;如果不需要SecurityHandler或SessionHandler,将它们从这个Handler链中去掉就可以了。
3.ScopedHandler
ScopedHandler相比如它的父类HandleWrapper最重大的改变是重写了handle()方法,在HandleWrapper链式handle()调用的基础上引入了doScope()流程。
@Override
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);
}
}
上面的代码中是根据_outScope是否为null来判断是走doScope()还是doHandle()方法的。_outScope是ScopedHandler引入的一个辅助变量,此外还有一个_nextScope变量。
protected ScopedHandler _outerScope;
protected ScopedHandler _nextScope;
下面通过距离来说明这两个变量的含义。我们知道ScopedHandler继承自HandlerWrapper,所以也是可以形成Handler链的,下面就是三个ScopedHandler对象形成的handler链:
ScopedHandler scopedA;
ScopedHandler scopedB;
ScopedHandler scopedC;
scopedA.setHandler(scopedB);
scopedB.setHandler(scopedC);
经过上面的设置之后,形成的handler链是:scopedA–>scopedB–>scopedC。这种情况下,scopedA的_nextScope=scopedB,scopedB的_nextScope=scopedC,scopedC的_nextScope是null(因为它是链尾,没有下一个节点),即_nextScope指向的是当前节点下一个节点的引用;而scopedA的_outerScope是null,scopedB和scopedC的_outScope都是指向scopedA,即_outScope指向的是当前handler链的头结点,对于头结点本身_outScope为null。
弄清楚了_outScope和_nextScope的含义,那么下一个问题就是对于一个ScopeHandler对象如何设置这两个值以及在何时设置这两个值。答案是在组件启动的时候,下面是ScopedHandler中的doStart()方法源码:
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.server.handler.HandlerWrapper#doStart()
*/
@Override
protected void doStart() throws Exception
{
try
{
//__outerScope是一个ThreadLocal变量,相当于线程中的全局变量
_outerScope=__outerScope.get();
if (_outerScope==null)
//将handler链头结点的引用填充进去
__outerScope.set(this);
super.doStart();
_nextScope=(ScopedHandler)getChildHandlerByClass(ScopedHandler.class);
}
finally
{
if (_outerScope==null)
__outerScope.set(null);
}
}
上面出现了__outerScope.get()这个方法,这里的__outerScope是ScopedHandler持有的一个ThreadLocal类型变量,在这里主要用于在线程中共享头结点引用的值,因为这个值是不能通过方法参数在handler链中传递的。现在还是以上面提到的scopedA–>scopedB–>scopedC这条handler链解释启动过程:
- scopedA调用start()方法,然后进入到它的doStart()方法,这时候__outerScope.get()取出来的是null(因为还没有进行填充),所以scopedA的_outScope的值为null,然后scopeA对象被填充到__scopeHanlder中,并调用super.doStart()。
- 因为scopedA是一个HandlerWrapper类型,并且持有的_handler引用指向的是scopedB,所以super.doStart()实际上会调用scopedB的start()方法;这个方法里同样会执行上面的doStart()逻辑,不过这次__outerScope.get()方法返回的不是null而是scopedA的引用,所以scopedB的_outScope被设置为scopedA。这里的super.dostart()会进入到scopedC,也会将scopedC的_outScope指向scopedA。
- 因为scopedC的_handler属性为null(因为它没有设置包装对象),所以super.doStart()会返回并执行
_nextScope=(ScopedHandler)getChildHandlerByClass(ScopedHandler.class)
这句代码,前面说过对于HandlerWrapper来说getChildHandlerByClass返回的就是其包装的_handler对象,这里返回的就是null。所以scopedC的_nextScope为null,这段方法结束返回scopedB中的doStart()中,同样执行上面这个方法,因为scopedB的_handler引用指向的是scopedC,所以返回的结果就是scopedC的引用即scopedB的_nextScope指向scopeC。 - 同理scopedA的_nextScope会指向scopedB。返回scopedA的doStart()方法之后,因为其_outScope为null,所以doStart()中finally部分的逻辑被触发,这个线程的ThreadLocal变量又被设置为null。
finally
{
if (_outerScope == null) {
__outerScope.set(null);
}
}
最后一个问题是在ScopedHandler形成的Handler链中是如何组织doScope()方法和doHandle()等方法调用的。实际上在ScopedHandler中对于doScope()和doHandle()方法是没有具体实现的,但是提供了nextHandle()和nextScope()两个方法,下面是它们的源码:
public abstract void doScope(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
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 abstract void doHandle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException;
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);
}
}
从nextHandle()和nextScope()方法大致上可以猜到doScope()和doHandle()的调用流程。下面通过ScopedHandler源码注释中提供的两个例子来说明下具体调用顺序:
* <p>For example if Scoped handlers A, B & C were chained together, then
* the calling order would be:<pre>
* A.handle(...)
* A.doScope(...)
* B.doScope(...)
* C.doScope(...)
* A.doHandle(...)
* B.doHandle(...)
* C.doHandle(...)
* <pre>
上面的例子是链上所有节点都是ScopedHandler的情况,下面是链上有部分节点不是ScopedHandler的情况:
* <p>If non scoped handler X was in the chained A, B, X & C, then
* the calling order would be:<pre>
* A.handle(...)
* A.doScope(...)
* B.doScope(...)
* C.doScope(...)
* A.doHandle(...)
* B.doHandle(...)
* X.handle(...)
* C.handle(...)
* C.doHandle(...)
* <pre>
无论哪种情况都能保证ScopeHandler链上的doScope()方法在dohandle()、handle()方法之前执行,并且不同对象的doScope()都是按对象在链上的先后执行的,doHandle()和handle()方法也是一样。这样的执行顺序可以使得组件可以在调用dohandle()或handle()处理请求之前进行一些初始化或配置工作,具体的应用场景会在后面分析具体组件的时候涉及到。
本文深入探讨Jetty的ScopedHandler,它是ContextHandler、SessionHandler等组件的基础。分析了HandlerContainer、AbstractHandlerContainer、HandlerWrapper的实现,特别强调ScopedHandler如何通过doScope()方法扩展Handler处理流程,并形成Handler链的机制。
3364

被折叠的 条评论
为什么被折叠?



