責任鏈模式(Chain Of Responsibility Pattern)
屬於行爲型模式
的一種,將請求沿着一條鏈傳遞,直到該鏈上的某個對象處理它爲止。html
<!-- more -->java
定義以下:一個請求有多個對象來處理,這些對象造成一條鏈,根據條件肯定具體由誰來處理,若是當前對象不能處理則傳遞給該鏈中的下一個對象,直到有對象處理它爲止。責任鏈模式
經過將請求和處理分離開來,以進行解耦。職責鏈模式結構的核心在於引入了一個抽象處理者。git
UML結構圖web
模式結構spring
提供對後續處理者的引用
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
除了要在應用中作相應配置外,還須要實現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
微信公衆號:battcn
(歡迎調戲)
關注公衆號:battcn
,回覆springboot
便可得到 <Spring Boot從入門到實戰 基礎實戰系列教程全集>
與 <2017最新spring boot 外賣實戰微信公衆平臺視頻教程>