浅析设计模式5 -- 责任链模式(下)

简介: 浅析设计模式5 -- 责任链模式(下)

更多精彩内容,欢迎观看:

浅析设计模式5 -- 责任链模式(上):https://developer.aliyun.com/article/1263229?groupCode=taobaotech


源码赏析


Servlet 约定在请求进入容器后、执行 Servlet.service() 方法前,可以通过 Filter 对 web 资源进行过滤、权限鉴别等处理。在 tomcat 启动时,先加载所有的过滤器信息;在 tomcat 收到请求时,再加载并执行整个过滤器的链路,当请求从链路中脱离后,才会进入真正的业务接口,如下图所示。

在 tomcat 中,每一个 Filter 都是一个具体处理者,不仅能处理请求、还能处理响应。对于 request 来说,责任链结构为 Filter1 -> Filter2 -> Filter3;而对于响应来说,责任链结构为 Filter3 -> Filter2 -> Filter1。这种双向处理的思想其实也很经典,下面将简单分析一下源码。

public interface Filter {    public default void init(FilterConfig filterConfig) throws ServletException {}    public void doFilter(ServletRequest request, ServletResponse response,            FilterChain chain) throws IOException, ServletException;    public default void destroy() {}}


Filter 为抽象处理者,提供了三个方法,其中 doFilter() 方法为处理方法,三个参数分别为请求、响应和链路管理器。接下来看一下链路管理器 FilterChain 的源码。


// FilterChainpublic interface FilterChain {    public void doFilter(ServletRequest request, ServletResponse response)            throws IOException, ServletException;}
// ApplicationFilterChainpublic final class ApplicationFilterChain implements FilterChain {        // 处理器链路,ApplicationFilterConfig 可以理解为对 Filter 的包装    private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];       // 当前处理器在链路中的索引    private int pos = 0;        // 调用入口    @Override    public void doFilter(ServletRequest request, ServletResponse response)        throws IOException, ServletException {        if( Globals.IS_SECURITY_ENABLED ) {            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 {                            // here                            internalDoFilter(req,res);                            return null;                        }                    }                );            } catch( PrivilegedActionException pe) {                Exception e = pe.getException();                if (e instanceof ServletException)                    throw (ServletException) e;                else if (e instanceof IOException)                    throw (IOException) e;                else if (e instanceof RuntimeException)                    throw (RuntimeException) e;                else                    throw new ServletException(e.getMessage(), e);            }        } else {            // here            internalDoFilter(request,response);        }    }        
// 开始处理    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(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;        }
        // 链路中没有更多过滤器了,开始进入 servlet        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 处理实际业务                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);            }        }    }}


ApplicationFilterChain 用数组来组织各处理者的先后顺序,并提供一个当前处理者在链路中的索引 pos 。当链路未在中途断开且当前处理者已是最后一个处理者时,调用 Servlet.service(request, response) 进入业务处理逻辑。作为用户,我们可以通过配置文件或者注入等方式,根据需要定义新的 Filter。


优缺点及适用场景

▐  优点

  1. 1 降低对象之间的耦合度。一个节点对象无须关心链的结构、到底是哪一个对象处理其请求,发送者和接收者也无须拥有对方的明确信息。
  2. 2 增强系统的可扩展性。可以根据需要增加新的请求处理类,满足开闭原则。
  3. 3 灵活地为对象指派职责。当工作流程变化时,可动态改变节点或调动节点次序,也可动态增删节点。
  4. 4 简化节点之间的连接。各节点只需保持一个指向其后继者的引用,避免使用众多 if 或 if…else 语句。
  5. 5 责任分担,符合类的单一职责原则。每个节点类只需处理自己该处理的工作,不该处理的传递给下一个节点类完成,各类的责任范围非常明确。


▐  缺点

  1. 1 不能保证每个请求一定被处理。一个请求没有明确的接收者,可能一直传到链的末端都得不到处理。
  2. 2 当责任链太长时,一个请求可能需要涉及多个处理者,系统性能会受到一定影响。
  3. 3 责任链建立的合理性需要由客户端来保证,增加了客户端的复杂性,也可能会因为错误设置而导致系统陷入死循环。


▐  适用场景

  1. 1 在运行时需要动态使用多个关联对象来处理同一次请求时。比如,请假流程、员工入职流程、编译打包发布上线流程等。
  2. 2 不想让使用者知道具体的处理逻辑时。比如,做权限校验的登录拦截器。
  3. 3 需要动态更换处理对象时。比如,工单处理系统、网关 API 过滤规则系统等。
  4. 4 职责链模式常被用在框架开发中,实现过滤器、拦截器等功能,使用者可以在不修改源码的情况下,添加新的过滤拦截功能。


团队介绍


我们是大聚划算技术团队。负责支持聚划算、百亿补贴、天天特卖、淘特价等业务。我们聚焦优惠和选购体验,通过数智化驱动形成更有效率和确定性的货品运营方法论,为消费者提供精选和极致性价比的商品,为商家提供更具爆发确定性的营销方案。

相关文章
|
6月前
|
设计模式 Java
【设计模式系列笔记】责任链模式
责任链模式是一种行为设计模式,它允许你将请求沿着处理者链进行传递,直到有一个处理者能够处理它。每个处理者都有一个对下一个处理者的引用。责任链模式常用于处理请求的场景,例如在一个请求需要经过多个步骤或者多个对象来处理的情况下。
75 0
|
6月前
|
设计模式 Java
【设计模式】责任链模式
【设计模式】责任链模式
|
6月前
|
设计模式
【设计模式】责任链模式
【1月更文挑战第27天】【设计模式】责任链模式
|
11天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
42 9
|
10天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
本教程详细讲解了Kotlin语法,适合需要深入了解Kotlin的开发者。对于希望快速上手Kotlin的读者,推荐查阅“简洁”系列教程。本文通过学生会经费申请的例子,介绍了责任链模式及其在Kotlin中的实现,并使用偏函数进行了改进,使代码更加简洁和灵活。
9 0
|
13天前
|
设计模式 JavaScript Scala
Kotlin - 改良设计模式 - 责任链模式
Kotlin - 改良设计模式 - 责任链模式
31 0
|
20天前
|
设计模式 JavaScript Scala
Kotlin学习笔记 - 改良设计模式 - 责任链模式
Kotlin学习笔记 - 改良设计模式 - 责任链模式
42 0
|
2月前
|
设计模式 缓存 监控
Java设计模式-责任链模式(17)
Java设计模式-责任链模式(17)
|
23天前
|
设计模式 JavaScript Scala
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
Kotlin教程笔记(55) - 改良设计模式 - 责任链模式
24 0
|
6月前
|
设计模式
设计模式之责任链模式
设计模式之责任链模式

热门文章

最新文章