资讯专栏INFORMATION COLUMN

一起学设计模式 - 责任链模式

SoapEye / 1708人阅读

摘要:责任链模式属于行为型模式的一种,将请求沿着一条链传递,直到该链上的某个对象处理它为止。责任链模式通过将请求和处理分离开来,以进行解耦。源码分析我们经常使用的就使用到了责任链模式,创建一个除了要在应用中做相应配置外,还需要实现接口。

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

概述

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

UML结构图

模式结构

Handler(抽象处理者): 定义一个处理请求的接口,提供对后续处理者的引用

ConcreteHandler(具体处理者): 抽象处理者的子类,处理用户请求,可选将请求处理掉还是传给下家;在具体处理者中可以访问链中下一个对象,以便请求的转发。

案例

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(测试类)

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

在源码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即可获得 <2017最新spring boot 外卖实战微信公众平台视频教程>

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/70629.html

相关文章

  • 函数式编程让你忘记设计模式

    摘要:面向对象常见的设计模式有策略模式模板方法观察者模式责任链模式以及工厂模式,使用表达式函数式编程思维有助于避免面向对象开发中的那些固定代码。 本文是一篇《Java 8实战》的阅读笔记,阅读大约需要5分钟。 有点标题党,但是这确实是我最近使用Lambda表达式的感受。设计模式是过去的一些好的经验和套路的总结,但是好的语言特性可以让开发者不去考虑这些设计模式。面向对象常见的设计模式有策略模式...

    or0fun 评论0 收藏0
  • 利用责任模式设计一个拦截器

    摘要:前言近期在做的拦截器功能,正好用到了责任链模式。通过官方图就可以非常清楚的看出是一个责任链模式用责任链模式设计一个拦截器对于拦截器来说使用责任链模式再好不过了。设置拦截器到责任链中时通过反射将的值保存到各个拦截器中。 showImg(https://segmentfault.com/img/remote/1460000016756077?w=1733&h=1300); 前言 近期在做 ...

    dreamans 评论0 收藏0
  • 忘了再看设计模式-行为型

    摘要:推文用设计模式解构三国是一种什么体验行为型设计模式一策略模式工厂模式优化结构状态模式随着状态改变而改变行为。推文状态机与状态模式责任链模式多个对象依次处理请求前者指定后者。代理模式代理针对一个对象,为了增加控制等中介双方都是多个,为了解耦。 策略模式 选择使用封装好的一系列算法,可相互替换。 类比:商店[Context]买完衣服买单[Stratege](现金[Concrete Stra...

    ShevaKuilin 评论0 收藏0
  • 轻松责任模式

    摘要:设计模式责任链模式顾名思义,责任链模式为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求的发送者和接收者进行解耦。增强给对象指派职责的灵活性。通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。 设计模式 - 责任链模式 顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型...

    cheukyin 评论0 收藏0
  • 一起设计模式 - 迭代器模式

    摘要:迭代器模式属于行为型模式的一种,提供一种方法访问一个容器中各个元素,而又不需要暴露该对象的内部细节。迭代器模式把在元素之间游走的责任交给迭代器,而不是聚合对象。 迭代器模式(Iterator Pattern)属于行为型模式的一种,提供一种方法访问一个容器中各个元素,而又不需要暴露该对象的内部细节。 概述 迭代器模式听起来可能感觉很陌生,但是实际上,迭代器模式是所有设计模式中最简单也是...

    JasonZhang 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<