java责任链设计模式及在tomca容器中的应用,第二部分

6 篇文章 0 订阅

责任链在tomcat 中的应用

Tomcat 中一个最容易发现的设计模式就是责任链模式,这个设计模式也是 Tomcat 中 Container 设计的基础,整个容器的就是通过一个链连接在一起,这个链一直将请求正确的传递给最终处理请求的那个 Servlet。
Tomcat 中容器责任链模式实现
在 tomcat 中这种设计模式几乎被完整的使用,tomcat 的容器设置就是责任链模式,从 Engine 到 Host 再到 Context 一直到 Wrapper 都是通过一个链传递请求。
Tomcat 中责任链模式的类结构图如下:
图 5. Tomcat 责任链模式的结构图
图 5. Tomcat 责任链模式的结构图
上图基本描述了四个子容器使用责任链模式的类结构图,对应的责任链模式的角色,Container 扮演抽象处理者角色,具体处理者由 StandardEngine 等子容器扮演。与标准的责任链不同的是,这里引入了 Pipeline 和 Valve 接口。他们有什么作用呢?
实际上 Pipeline 和 Valve 是扩展了这个链的功能,使得在链往下传递过程中,能够接受外界的干预。Pipeline 就是连接每个子容器的管子,里面传递的 Request 和 Response 对象好比管子里流的水,而 Valve 就是这个管子上开的一个个小口子,让你有机会能够接触到里面的水,做一些额外的事情。
为了防止水被引出来而不能流到下一个容器中,每一段管子最后总有一个节点保证它一定能流到下一个子容器,所以每个容器都有一个 StandardXXXValve。只要涉及到这种有链式是处理流程这是一个非常值得借鉴的模式

filter责任链实现
我们看Tomcat中对于此模式是如何实现的。

在Filter的使用中,我们会注意到其接口中包含这样一个方法
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
我们看到,这个方法中,除了向下传递请递request和response之外,还传了另一个FilterChain对象。每次当前Filter的逻辑处理完成后,我们一般会调用FilterChain的doFilter方法,以执行下一个Filter的逻辑。这里需要注意的是,可能这个FilterChain的接口方法也叫doFilter容易引起误解,其实这个方法的声明如下:
/**
* Causes the next filter in the chain to be invoked, or if the calling
* filter is the last filter in the chain, causes the resource at the end of
* the chain to be invoked.
*/
public void doFilter(ServletRequest request, ServletResponse response);

如果这里称之为invokeFilter或者executeFilter也许更好理解些。

那么,每一次,一个Filter执行完毕后,FilterChain的doFilter是如何确认下一个Filter该谁去执行了呢?
奥秘就在这里,即FilterChain接口的实现。
/**
* Invoke the next filter in this chain, passing the specified request
* and response. If there are no more filters in this chain, invoke
* the service() method of the servlet itself.
*
*/
public void doFilter(ServletRequest request, ServletResponse response){

if( Globals.IS_SECURITY_ENABLED ) {//注意这里是启用了SecurityManager,了解详情可以后台回复关键字003查看。
    final ServletRequest req = request;
    final ServletResponse res = response;
    try {
        java.security.AccessController.doPrivileged(
            new java.security.PrivilegedExceptionAction<Void>() {
                @Override
                public Void run()
                    throws ServletException, IOException {
                    internalDoFilter(req,res);
                    return null;
              } });
    } catch( PrivilegedActionException pe) { }
} else {
 internalDoFilter(request,response);//默认每次调用的处理方法在这里
}}

private void internalDoFilter(ServletRequest request,
ServletResponse response){
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
Filter filter = null;
filter = filterConfig.getFilter();
filter.doFilter(request, response, this);
return;
}

// We fell off the end of the chain -- call the servlet instance
    if ((request instanceof HttpServletRequest) &&
        (response instanceof HttpServletResponse)) {
            servlet.service(request, response);
    } else {
        servlet.service(request, response);
    }}

我们看到,在真正处理FilterChain的控制中,是通过pos和n这两个参数来判断的。两者的声明如下:
/**
* The int which is used to maintain the current position
* in the filter chain.
*/
private int pos = 0;

/**
* The int which gives the current number of filters in the chain.
*/
private int n = 0;

我们看到,一个标识当前处理的Filter,一个标识chain中的总filter数。

在chain中的Filter都执行完成后,pos < n 的逻辑不再执行,跳到执行后面真正的Servlet的请求处理。

而每个Filter,可以在filterChain执行前后分别进行预处理和后处理。是因为每个filter调用,最后类似于递归调用,在filter的doFilter执行完毕后逻辑中会有return操作,保证不向下执行到Servlet的逻辑中。

了解了Filter的执行原理以及责任链模式的基本概念,我们自己要使用这个模式,只需要保证各个链实现相同的接口,接口方法中每次将Chain传递下去,即可很好的实现。控制Chain执行的逻辑中,可以通过数组或者List来存储整个链的元素,像Tomcat这样:
/**
* Filters.
*/
private ApplicationFilterConfig[] filters =
new ApplicationFilterConfig[0];

在控制中,每次取出下一个元素执行,就可以实现责任链了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值