一块儿学设计模式 - 责任链模式

责任链模式(Chain Of Responsibility Pattern)属于行为型模式的一种,将请求沿着一条传递,直到该上的某个对象处理它为止。html

<!-- more -->java

概述

定义以下:一个请求有多个对象来处理,这些对象造成一条链,根据条件肯定具体由谁来处理,若是当前对象不能处理则传递给该链中的下一个对象,直到有对象处理它为止。责任链模式经过将请求和处理分离开来,以进行解耦。职责链模式结构的核心在于引入了一个抽象处理者。git

UML结构图web

责任链模式UML图

模式结构spring

  • Handler(抽象处理者): 定义一个处理请求的接口,提供对后续处理者的引用
  • ConcreteHandler(具体处理者): 抽象处理者的子类,处理用户请求,可选将请求处理掉仍是传给下家;在具体处理者中能够访问链中下一个对象,以便请求的转发。

案例

UML图以下:设计模式

UML图

1.定义AbstractHandler(抽象处理者),使子类造成一条链数组

public abstract class AbstractHandler {

    private AbstractHandler handler;

    public abstract void handleRequest(String condition);

    public AbstractHandler getHandler() {
        return handler;
    }

    public void setHandler(AbstractHandler handler) {
        this.handler = handler;
    }
}

2.建立若干个ConcreteHandler(具体处理者)继承AbstractHandler,在当前处理者对象没法处理时,将执行权传给下一个处理者对象安全

public class ConcreteHandlerA extends AbstractHandler {

    @Override
    public void handleRequest(String condition) {
        if (condition.equals("A")) {
            System.out.println("ConcreteHandlerA处理");
        } else {
            System.out.println("ConcreteHandlerA不处理,由其余的Handler处理");
            super.getHandler().handleRequest(condition);
        }
    }
}

public class ConcreteHandlerB extends AbstractHandler {

    @Override
    public void handleRequest(String condition) {
        if (condition.equals("B")) {
            System.out.println("ConcreteHandlerB处理");
        } else {
            System.out.println("ConcreteHandlerB不处理,由其余的Handler处理");
            super.getHandler().handleRequest(condition);
        }
    }
}

public class ConcreteHandlerZ extends AbstractHandler {
    @Override
    public void handleRequest(String condition) {
        //通常是最后一个处理者
        System.out.println("ConcreteHandlerZ处理");
    }
}

3.建立ChainClient(测试类)springboot

public class ChainClient {

    public static void main(String[] args) {
        AbstractHandler handlerA = new ConcreteHandlerA();
        AbstractHandler handlerB = new ConcreteHandlerB();
        AbstractHandler handlerZ = new ConcreteHandlerZ();
        // 如A处理不掉转交给B
        handlerA.setHandler(handlerB);
        handlerB.setHandler(handlerZ);
        handlerA.handleRequest("Z");
    }

}

4.运行效果微信

----------------------handleRequest("A")-------------------------
ConcreteHandlerA处理
----------------------handleRequest("B")-------------------------
ConcreteHandlerA不处理,由其余的Handler处理
ConcreteHandlerB处理
----------------------handleRequest("Z")-------------------------
ConcreteHandlerA不处理,由其余的Handler处理
ConcreteHandlerB不处理,由其余的Handler处理
ConcreteHandlerZ处理

能够看出,客户端建立了三个处理者对象,并指定第一个处理者对象的下家是第二个处理者对象,第二个处理者对象的下家是第三个处理者对象。而后客户端将请求传递给第一个处理者对象。

因为本示例的传递逻辑很是简单:只要有下家,就传给下家处理;若是没有下家,就自行处理。所以,第一个处理者对象接到请求后,会将请求传递给第二个处理者对象。因为第二个处理者对象没有下家,因而自行处理请求。活动时序图以下所示。

时序图

纯与不纯

  • 纯:要么承担所有责任,要么将责任推给下家,不容许出现某一个具体处理者对象在承担了一部分或所有责任后又将责任向下传递的状况。
  • 不纯:容许某个请求被一个具体处理者部分处理后再向下传递,或者一个具体处理者处理完某请求后其后继处理者能够继续处理该请求,并且一个请求能够最终不被任何处理者对象所接收。

Filter源码分析

咱们常用的Filter就使用到了责任链模式,建立一个Filter除了要在应用中作相应配置外,还须要实现javax.servlet.Filter接口。

@Configuration
public class MyFilter implements Filter {

    private final static Logger LOGGER = LoggerFactory.getLogger(MyFilter.class);

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LOGGER.info("init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        LOGGER.info("doFilter");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {
        LOGGER.info("destroy");
    }
}

使用DEBUG模式所看到的结果以下:

Filter应用

Filter

在源码ApplicationFilterChain中,定义了一个ApplicationFilterConfig的数组来存放全部的Filter,使之造成链状

public final class ApplicationFilterChain implements FilterChain {
    // 扩容规则
    public static final int INCREMENT = 10;
    // Filter集,默认大小为 0 个  
    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
}

ApplicationFilterConfig 装载规则

在应用首次启动时,会自动实例化对象,并从web应用中读取配置的Filter的信息,而后装进该容器。

public final class ApplicationFilterConfig implements FilterConfig, Serializable {
    // 省略代码...
}

ApplicationFilterConfig 扩容规则

//将过滤器添加到在此链条中执行的过滤器集合中。
void addFilter(ApplicationFilterConfig filterConfig) {

    // 防止屡次添加相同的过滤器
    for(ApplicationFilterConfig filter:filters)
        if(filter==filterConfig)
            return;

    if (n == filters.length) {
        // 定义一个在原基础之上 +10 的新数组
        ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT];
        // 将源数组的元素拷贝到目标数组中去
        System.arraycopy(filters, 0, newFilters, 0, n);
        // 从新赋值
        filters = newFilters;
    }
    //将变量filterConfig放入ApplicationFilterConfig数组中,并将当前过滤器链里面拥有的过滤器数目+1
    filters[n++] = filterConfig;
}

addFilter 的使用

public static ApplicationFilterChain createFilterChain(ServletRequest request,Wrapper wrapper, Servlet servlet) {

        //若是没有 servlet 要执行,则返回null
        if (servlet == null)
            return null;

        // 建立和初始化过滤器链对象
        ApplicationFilterChain filterChain = null;
        if (request instanceof Request) {
            Request req = (Request) request;
            if (Globals.IS_SECURITY_ENABLED) {
                // 为了安全起见:不要回收
                filterChain = new ApplicationFilterChain();
            } else {
                filterChain = (ApplicationFilterChain) req.getFilterChain();
                if (filterChain == null) {
                    filterChain = new ApplicationFilterChain();
                    req.setFilterChain(filterChain);
                }
            }
        } else {
            // 调度程序在使用中
            filterChain = new ApplicationFilterChain();
        }

        filterChain.setServlet(servlet);
        filterChain.setServletSupportsAsync(wrapper.isAsyncSupported());

        // 获取过滤器上下文映射
        StandardContext context = (StandardContext) wrapper.getParent();
        FilterMap filterMaps[] = context.findFilterMaps();

        // 若是没有过滤器映射,就认为当前执行完成
        if ((filterMaps == null) || (filterMaps.length == 0))
            return (filterChain);

        // 获取匹配的过滤器映射信息
        DispatcherType dispatcher =
                (DispatcherType) request.getAttribute(Globals.DISPATCHER_TYPE_ATTR);

        String requestPath = null;
        Object attribute = request.getAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR);
        if (attribute != null){
            requestPath = attribute.toString();
        }

        String servletName = wrapper.getName();

        // 将相关路径映射的过滤器添加到此过滤器链中
        for (int i = 0; i < filterMaps.length; i++) {
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            if (!matchFiltersURL(filterMaps[i], requestPath))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // 添加与servlet名称匹配的筛选器
        for (int i = 0; i < filterMaps.length; i++) {
            if (!matchDispatcher(filterMaps[i] ,dispatcher)) {
                continue;
            }
            if (!matchFiltersServlet(filterMaps[i], servletName))
                continue;
            ApplicationFilterConfig filterConfig = (ApplicationFilterConfig)
                context.findFilterConfig(filterMaps[i].getFilterName());
            if (filterConfig == null) {
                // FIXME - log configuration problem
                continue;
            }
            filterChain.addFilter(filterConfig);
        }

        // 返回完整的过滤器链
        return filterChain;
    }

createFilterChain 的调用

final class StandardWrapperValve extends ValveBase {
    public final void invoke(Request request, Response response) throws IOException, ServletException {
        // 省略代码...
        // 为这个请求建立过滤器链
        ApplicationFilterFactory factory = ApplicationFilterFactory.getInstance();
        ApplicationFilterChain filterChain = factory.createFilterChain(request, wrapper, servlet);
        // 省略代码...
        filterChain.doFilter(request.getRequest(), response.getResponse());
    }
}

执行流程

在StandardWrapperValue类的invoke()方法中调用ApplicationFilterChai类的createFilterChain()方法
在ApplicationFilterChai类的createFilterChain()方法中调用ApplicationFilterChain类的addFilter()方法
在ApplicationFilterChain类的addFilter()方法中给ApplicationFilterConfig数组赋值。

执行流程

最后一步

doFilter()方法中最后会调用一个internalDoFilter()方法,目的就是执行ApplicationFilterChain中的所有过滤器,从代码中能够发现它调用了doFilter,而在doFilter又会调用internalDoFilter 从而使全部的Filter都得以调用

private void internalDoFilter(ServletRequest request,ServletResponse response) throws IOException, ServletException {

    // 若是存在下一个,继续调用下一个过滤器
    if (pos < n) {
        ApplicationFilterConfig filterConfig = filters[pos++];
        try {
            Filter filter = filterConfig.getFilter();

            if (request.isAsyncSupported() && "false".equalsIgnoreCase(
                    filterConfig.getFilterDef().getAsyncSupported())) {
                request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
            }
            if( Globals.IS_SECURITY_ENABLED ) {
                final ServletRequest req = request;
                final ServletResponse res = response;
                Principal principal =
                    ((HttpServletRequest) req).getUserPrincipal();

                Object[] args = new Object[]{req, res, this};
                SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
            } else {
                // 此处调用Filter的doFilter()方法  / 而 doFilter 又会调用 internalDoFilter 直到调用完全部的过滤器
                filter.doFilter(request, response, this);
            }
        } catch (IOException | ServletException | RuntimeException e) {
            throw e;
        } catch (Throwable e) {
            e = ExceptionUtils.unwrapInvocationTargetException(e);
            ExceptionUtils.handleThrowable(e);
            throw new ServletException(sm.getString("filterChain.filter"), e);
        }
        return;
    }

    // 从最后一个开始调用
    try {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest.set(request);
            lastServicedResponse.set(response);
        }

        if (request.isAsyncSupported() && !servletSupportsAsync) {
            request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,
                    Boolean.FALSE);
        }
        // 包装请求
        if ((request instanceof HttpServletRequest) &&
                (response instanceof HttpServletResponse) &&
                Globals.IS_SECURITY_ENABLED ) {
            final ServletRequest req = request;
            final ServletResponse res = response;
            Principal principal =
                ((HttpServletRequest) req).getUserPrincipal();
            Object[] args = new Object[]{req, res};
            SecurityUtil.doAsPrivilege("service",
                                       servlet,
                                       classTypeUsedInService,
                                       args,
                                       principal);
        } else {
            servlet.service(request, response);
        }
    } catch (IOException | ServletException | RuntimeException e) {
        throw e;
    } catch (Throwable e) {
        e = ExceptionUtils.unwrapInvocationTargetException(e);
        ExceptionUtils.handleThrowable(e);
        throw new ServletException(sm.getString("filterChain.servlet"), e);
    } finally {
        if (ApplicationDispatcher.WRAP_SAME_OBJECT) {
            lastServicedRequest.set(null);
            lastServicedResponse.set(null);
        }
    }
}

总结

职责链模式经过创建一条链来组织请求的处理者,请求将沿着链进行传递,请求发送者无须知道请求在什么时候、何处以及如何被处理,实现了请求发送者与处理者的解耦。在软件开发中,若是遇到有多个对象能够处理同一请求时能够应用职责链模式,例如在Web应用开发中建立一个过滤器(Filter)链来对请求数据进行过滤,在工做流系统中实现公文的分级审批等等,使用职责链模式能够较好地解决此类问题。

优势

  • 下降耦合度,分离了请求与处理,无须知道是哪一个对象处理其请求
  • 简化对象的相互链接,仅保持一个指向后者的引用,而不需保持全部候选接受者的引用
  • 扩展容易,新增具体请求处理者,只须要在客户端从新建链便可,无需破坏原代码

缺点

  • 若是请求没有明确的接收者,那么就不能保证它必定会被处理,该请求可能一直到链的末端都得不处处理;一个请求也可能因职责链没有被正确配置而得不处处理
  • 较长的职责链,请求的处理可能涉及到多个处理对象,系统性能将受到必定影响,并且在进行代码调试时不太方便。
  • 若是建链不当,可能会形成循环调用,将致使系统陷入死循环。

金无足赤,人无完人。就像全部的设计模式同样,有优势优缺点,可是总的来讲优势一定大于缺点或者说缺点相对于优势来讲更可控。

说点什么

参考文献:http://www.cnblogs.com/java-my-life/archive/2012/05/28/2516865.html

全文代码:https://gitee.com/battcn/design-pattern/tree/master/Chapter11/battcn-chain-responsibility

  • 我的QQ:1837307557
  • battcn开源群(适合新手):391619659

微信公众号:battcn(欢迎调戏)

福利

关注公众号:battcn,回复springboot便可得到 <Spring Boot从入门到实战 基础实战系列教程全集><2017最新spring boot 外卖实战微信公众平台视频教程>

相关文章
相关标签/搜索