责任链模式

    技术2025-06-22  16

    1、责任链模式是适用于对一个对象的链式加工处理,在处理的链中可以随时按需终止。非常使用处理http请求。

    2、模式优点

    易于扩展:这点对于设计框架特别重要,spring框架给客户提供了Filter接口,客户实现并注册,spring框架启动的时候就可以将客户的实现扫描加载到框架中。

    结构清晰,方便理解,易于阅读:这点特别有利于项目的维护。

    3、实现方法

    先看在java扩展包中servert定义的责任链接口和Filter接口

    package javax.servlet; public interface FilterChain { //request:http请求 response: http响应 public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException; } public interface Filter { public void init(FilterConfig filterConfig) throws ServletException; //业务逻辑实现函数 public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException; public void destroy(); }

    通过idea工具查看FilterChain的实现类: 

     先看在Tomcat 中的实现类ApplicationFilterChain:

    class ApplicationFilterChain implements FilterChain { //使用threadlocal可以看出ApplicationFilterChain是线程共享的,是线程安全的 private static final ThreadLocal<ServletRequest> lastServicedRequest; private static final ThreadLocal<ServletResponse> lastServicedResponse; //Filter配置数组,ApplicationFilterConfig组合Filter相关的功能,提供了Filter的功能 private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; //每次Filter数组增加的数量,addFilter当fiter数组容量不够的时候,先扩容,再copy,再加入新filter public static final int INCREMENT = 10; //当前处理Filter的位置索引 private int pos = 0; 责任链Fiters的数量 private int n = 0; //实际工作的doFilter函数,删除业务代码,保留责任链处理流程 private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { //如果pos<n,表示还有Filter处理request if (pos < n) { //获取对应的Filter,位置指数加1,然后调用Filter的doFilter业务处理函数 ApplicationFilterConfig filterConfig = filters[pos++]; Filter filter = filterConfig.getFilter(); filter.doFilter(request, response, this); } //责任链执行完毕,最后还要调用servlet处理request请求 //这里的servlet,根据request中的url映射到常见的有DispathcherServlet,DruidViewServlet servlet.service(request, response); } // 增加filter函数 void addFilter(ApplicationFilterConfig filterConfig) { //避免加入重复的filter for (ApplicationFilterConfig filter : filters) if (filter == filterConfig) return; //如果filter数组已经满了,怎执行扩容,复制原filters数组到新数组,最后将新filter加到数组末尾 if (n == filters.length) { ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT]; System.arraycopy(filters, 0, newFilters, 0, n); filters = newFilters; } filters[n++] = filterConfig; } }

    1、从上面代码可以看出,ApplicationFilterChain用动态数组保存Filter,按实际需要扩展数组,可以减少内存资源的消耗。

     

    4、进阶:

    用链表实现,并给filter添加排序功能,不是简单的将新Filter加入到尾部。

    另外也可以用链表实现:想比较与动态数组扩容方式,避免了数组扩容带来的复制时间开销。

    package com.dengfangwen.org; public class FilterChain { Filter header; public void doFilter(Object o) { Filter f = header; while (f != null) { f.doFilter(o); f = f.next; } } public void addFilter(Filter f) { if (header == null) { f.next = null; header = f; } else if (f.order <= header.order) { //需要插入到头节点位置 f.next = header; header = f; } else { Filter pre = header; Filter cur = pre.next; while (cur != null) { if (f.order <= cur.order) { //插入到当前位置 pre.next = f; f.next = cur; } else { pre = cur; cur = pre.next; } } //需要加到尾部 if (cur == null) { f.next = null; pre.next = f; } } } public static void main(String[] argc) { FilterChain fc = new FilterChain(); fc.addFilter(new FilterImpl("Filter 2", 2, null)); fc.addFilter(new FilterImpl("Filter 3", 3, null)); fc.addFilter(new FilterImpl("Filter 1", 1, null)); fc.doFilter(new Object()); } } abstract class Filter { protected Filter next; protected String filterName; protected int order; abstract void doFilter(Object o); Filter(String name, int order, Filter next) { filterName = name; this.next = next; this.order = order; } } class FilterImpl extends Filter { FilterImpl(String name, int order, Filter next) { super(name, order, next); } public void doFilter(Object o) { System.out.println("filter " + (filterName != null ? filterName : "null") + " order: " + order + " in process"); } }

    filter 按照order 顺序处理:

    Processed: 0.009, SQL: 9