Intercepting Filter模式在Servlet的Filter中的实现QJetty版本Q?/h2>其中Servlet的Filter在Jetty的实C使用数组存储FilterQFilter末尾可以使用Servlet实例处理真正的业务逻辑Q在程控制上,使用FilterChain的doFilterҎ来实现。如FilterChain在Jetty中的实现Q?br />
public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException
// pass to next filter
if (_filter < LazyList.size(_chain)) {
FilterHolder holder= (FilterHolder)LazyList.get(_chain, _filter++);
Filter filter= holder.getFilter();
filter.doFilter(request, response, this);
return;
}
// Call servlet
HttpServletRequest srequest = (HttpServletRequest)request;
if (_servletHolder != null) {
_servletHolder.handle(_baseRequest,request, response);
}
}
q里Q_chain实际上是一个Filter的ArrayListQ由FilterChain调用doFilter()启动调用W一个Filter的doFilter()ҎQ在实际的Filter实现中,需要手动的调用FilterChain.doFilter()Ҏ来启动下一个Filter的调用,利用Ҏ调用的进栈出栈的Ҏ实现Request的pre-process和Response的post-process处理。如果不调用FilterChain.doFilter()ҎQ则表示不需要调用之后的FilterQ流E从当前Filterq回Q在它之前的Filter的FilterChain.doFilter()调用之后的逻辑反向处理直到W一个Filter处理完成而返回?br />public class MyFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// pre-process ServletRequest
chain.doFilter(request, response);
// post-process Servlet Response
}
}
整个Filter铄处理程如下Q?br />
Intercepting Filter模式在Netty3中的实现
Netty3在DefaultChannelPipeline中实CIntercepting Filter模式Q其中ChannelHandler是它的Filter。在Netty3的DefaultChannelPipeline中,使用一个以ChannelHandlerContext点的双向链表来存储ChannelHandlerQ所有的横切面逻辑和实际业务逻辑都用ChannelHandler表达Q在控制程上用ChannelHandlerContext的sendDownstream()和sendUpstream()Ҏ来控制流E。不同于Servlet的FilterQChannelHandler有两个子接口QChannelUpstreamHandler和ChannelDownstreamHandler分别用来hq入时的处理程和响应出L的处理流E。对于Client的请求,从DefaultChannelPipeline的sendUpstream()Ҏ入口Q?br />public void sendDownstream(ChannelEvent e) {
DefaultChannelHandlerContext tail = getActualDownstreamContext(this.tail);
if (tail == null) {
try {
getSink().eventSunk(this, e);
return;
} catch (Throwable t) {
notifyHandlerException(e, t);
return;
}
}
sendDownstream(tail, e);
}
void sendDownstream(DefaultChannelHandlerContext ctx, ChannelEvent e) {
if (e instanceof UpstreamMessageEvent) {
throw new IllegalArgumentException("cannot send an upstream event to downstream");
}
try {
((ChannelDownstreamHandler) ctx.getHandler()).handleDownstream(ctx, e)
} catch (Throwable t) {
e.getFuture().setFailure(t);
notifyHandlerException(e, t);
}
}
如果有响应消息,该消息从DefaultChannelPipeline的sendDownstream()Ҏ为入口:
public void sendUpstream(ChannelEvent e) {
DefaultChannelHandlerContext head = getActualUpstreamContext(this.head);
if (head == null) {
return;
}
sendUpstream(head, e);
}
void sendUpstream(DefaultChannelHandlerContext ctx, ChannelEvent e) {
try {
((ChannelUpstreamHandler) ctx.getHandler()).handleUpstream(ctx, e);
} catch (Throwable t) {
notifyHandlerException(e, t);
}
}
在实际实现ChannelUpstreamHandler或ChannelDownstreamHandlerӞ调用ChannelHandlerContext中的sendUpstream或sendDownstreamҎ控制流E交l下一个ChannelUpstreamHandler或下一个ChannelDownstreamHandlerQ或调用Channel中的writeҎ发送响应消息?br />public class MyChannelUpstreamHandler implements ChannelUpstreamHandler {
public void handleUpstream(ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
// handle current logic, use Channel to write response if needed.
// ctx.getChannel().write(message);
ctx.sendUpstream(e);
}
}
public class MyChannelDownstreamHandler implements ChannelDownstreamHandler {
public void handleDownstream(
ChannelHandlerContext ctx, ChannelEvent e) throws Exception {
// handle current logic
ctx.sendDownstream(e);
}
}
当ChannelHandler向ChannelPipelineContext发送事件时Q其内部从当前ChannelPipelineContext
节点出发扑ֈ下一个ChannelUpstreamHandler或ChannelDownstreamHandler实例Qƈ向其发?
ChannelEventQ对于Downstream链,如果到达铑ְQ则ChannelEvent发送给ChannelSinkQ?br />public void sendDownstream(ChannelEvent e) {
DefaultChannelHandlerContext prev = getActualDownstreamContext(this.prev);
if (prev == null) {
try {
getSink().eventSunk(DefaultChannelPipeline.this, e);
} catch (Throwable t) {
notifyHandlerException(e, t);
}
} else {
DefaultChannelPipeline.this.sendDownstream(prev, e);
}
}
public void sendUpstream(ChannelEvent e) {
DefaultChannelHandlerContext next = getActualUpstreamContext(this.next);
if (next != null) {
DefaultChannelPipeline.this.sendUpstream(next, e);
}
}
正是因ؓq个实现Q如果在一个末ChannelUpstreamHandler中先U除自己Q在向末添加一个新的ChannelUpstreamHandlerQ它是无效的Q因为它的next已经在调用前固定设|ؓnull了?br />
在DefaultChannelPipeline的ChannelHandler链条的处理流EؓQ?br />
在这个实CQ不像Servlet的Filter实现利用Ҏ调用栈的q出栈来完成pre-process和post-processQ而是在进ȝ铑֒出来的链各自调用handleUpstream()和handleDownstream()ҎQ这样会引v调用栈其实是两条铄dQ因而需要注意这条链的总长度。这样做的好处是q条ChannelHandler的链不依赖于Ҏ调用栈,而是在DefaultChannelPipeline内部本n的链Q因而在handleUpstream()或handleDownstream()可以随时执行流E{发给其他U程或线E池Q只需要保留ChannelPipelineContext引用Q在处理完成后用q个ChannelPipelineContext重新向这条链的后一个节点发送ChannelEventQ然而由于Servlet的Filter依赖于方法的调用栈,因而方法返回意味着所有执行完成,q种限制在异步编E中会引起问题,因而Servlet?.0后引入了Async的支持?br />Intercepting Filter模式的缺?/h2>单提一下这个模式的~点Q?br />1. 相对传统的编E模型,q个模式有一定的学习曲线Q需要很好的理解该模式后才能灉|的应用它来编E?br />2. 需要划分不同的逻辑C同的Filter中,q有些时候ƈ不是那么Ҏ?br />3. 各个Filter之间׃n数据变得困难。在Netty3中可以自定义自己的ChannelEvent来实现自定义消息的传输,或者用ChannelPipelineContext的Attachment字段来实现消息传输,而Servlet中的Filter则没有提供类似的机制Q如果不是可以配|的数据在Config中传递,其他时候的数据׃n需要其他机刉合完成?br />