爲了解耦的任務校驗,將校驗對象連成一個鏈,沿着這個鏈進行訪問,直到有一個對象處理位置;
1.按照必定的順序執行判斷;前端
2.避免校驗對象之間耦合關係;java
3.不用擔憂沒有代碼沒有執行到;設計模式
這段代碼總共作了三件事:1.過濾器鏈建立;2.過濾鏈逐個過濾;3.釋放過濾鏈資源;數組
private void invoke(ServletRequest request, ServletResponse response, State state) throws IOException, ServletException { //。。。。。。。。前面的代碼省略 // Get the FilterChain Here ApplicationFilterChain filterChain = ApplicationFilterFactory.createFilterChain(request, wrapper, servlet); //建立過濾器校驗鏈條 // Call the service() method for the allocated servlet instance try { // for includes/forwards if ((servlet != null) && (filterChain != null)) { filterChain.doFilter(request, response); //進行過濾器校驗 } // Servlet Service Method is called by the FilterChain } catch (ClientAbortException e) { //。。。。。。。省略中間錯誤判斷代碼 } // Release the filter chain (if any) for this request try { if (filterChain != null) filterChain.release();//釋放過濾器資源 } catch (Throwable e) { ExceptionUtils.handleThrowable(e); wrapper.getLogger().error(sm.getString("standardWrapper.releaseFilters", wrapper.getName()), e); // FIXME: Exception handling needs to be similar to what is in the StandardWrapperValue } //。。。。。。。。。後面的代碼省略 }
從下面能夠看出主要是一下操做:app
1.初始化ApplicatFilterChain 過濾器校驗鏈;ide
2.從上下文環境中,獲取以前配置的過濾器數據;ui
3.將符合URL,serveletName的過濾器配置到ApplicationFilterChain中this
public static ApplicationFilterChain createFilterChain(ServletRequest request, Wrapper wrapper, Servlet servlet) { // If there is no servlet to execute, return null if (servlet == null) return null; // Create and initialize a filter chain object 初始化鏈式對象 ApplicationFilterChain filterChain = null; if (request instanceof Request) { Request req = (Request) request; if (Globals.IS_SECURITY_ENABLED) { // Security: Do not recycle filterChain = new ApplicationFilterChain(); } else { filterChain = (ApplicationFilterChain) req.getFilterChain(); if (filterChain == null) { filterChain = new ApplicationFilterChain(); req.setFilterChain(filterChain); } } } else { // Request dispatcher in use filterChain = new ApplicationFilterChain(); } filterChain.setServlet(servlet); filterChain.setServletSupportsAsync(wrapper.isAsyncSupported()); // Acquire the filter mappings for this Context 獲取過濾器配置的上下文 StandardContext context = (StandardContext) wrapper.getParent(); FilterMap filterMaps[] = context.findFilterMaps(); // If there are no filter mappings, we are done if ((filterMaps == null) || (filterMaps.length == 0)) return filterChain; // Acquire the information we will need to match filter mappings 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(); // Add the relevant path-mapped filters to this filter chain 將符合需求的過濾器加入到過濾鏈中 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); } // Add filters that match on servlet name second 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 the completed filter chain return filterChain; }
這個方法比較簡單:1.數組擴容;2.增長新的過濾器;spa
private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];//過濾器存儲的實體類 private int pos = 0;//當前過濾位置 private int n = 0;//存儲的過濾器的總數 public static final int INCREMENT = 10; void addFilter(ApplicationFilterConfig filterConfig) { // Prevent the same filter being added multiple times for(ApplicationFilterConfig filter:filters) if(filter==filterConfig) return; if (n == filters.length) { ApplicationFilterConfig[] newFilters = new ApplicationFilterConfig[n + INCREMENT]; System.arraycopy(filters, 0, newFilters, 0, n); filters = newFilters; } filters[n++] = filterConfig; }
處理過程:設計
1.獲取pos位置的過濾器;
2.Filter執行,將當前過濾鏈對象,做爲參數進行傳遞;
3.pos過濾器後移1位進行調用,直到pos大於總過濾器位置;
@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 { 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 { internalDoFilter(request,response); } } //實際處理過濾任務的方法 private void internalDoFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException { // Call the next filter if there is one if (pos < n) { ApplicationFilterConfig filterConfig = filters[pos++];//pos默認是從0開始的,調用後+1 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; } //。。。。。。。。。。省略部分代碼 }
業務需求:前端傳來數據,動態SQL拼接,判斷SQL各個部分是否數據有問題;
/** * 參數校驗鎖鏈管理 * @param * @author lpf */ public interface CheckChain{ public abstract void doCheck(Param param) throws Exception; }
public interface Param<T extends Param> { public abstract <T> T get(); }
@Service public interface CheckFilter<T extends Param> { /** * 參數校驗方法 * @param chain * @return */ public abstract void checkParam(Param<T> param, CheckChain chain) throws Exception; }
/** * 默認鏈式檢查 */ public class DefaultCheckChain implements CheckChain { /** * */ private ParamCheckWapper[] wappers = new ParamCheckWapper[0]; private static final int INCREMENT = 10; private int n = 0; private int pos = 0; //進行鏈式檢查 @Override public void doCheck(Param filed) throws Exception { if(pos < n){ ParamCheckWapper wapper = wappers[pos++]; CheckFilter paramCheck = wapper.getParamCheck(); Assert.notNull(paramCheck,"鏈式類不能爲空"); paramCheck.checkParam(filed,this); } } /** * 增長要進行過濾處理的類 * @param checkWapper */ public void addCheck(ParamCheckWapper checkWapper){ for(ParamCheckWapper wapper : wappers){ if(wapper == checkWapper){return;} ; } if(n == wappers.length){ ParamCheckWapper[] newWappers = new ParamCheckWapper[n + INCREMENT]; System.arraycopy(wappers, 0, newWappers, 0, n); wappers = newWappers; } wappers[n++] = checkWapper; } }
/** * select參數校驗 * @author lpf * @since 2019-11-08 */ public class SelectParamCheck implements CheckFilter<CheckParam> { /** * 參數校驗 * @param param * @param chain */ @Override public void checkParam(Param<CheckParam> param, CheckChain chain) throws Exception{ CheckParam checkParam = param.get(); List<SelectField> selects = checkParam.getSelect(); List<String> columns = checkParam.getColumnList(); //對select參數進行校驗 selects.forEach(select -> { String filed = select.getFiled().toLowerCase(); boolean flag = columns.contains(filed); if(!flag) throw new RuntimeException(select.getFiled()+"不存在,請刷新頁面從新選擇查詢字段!!!"); }); }
@Service public class SearchConfigService { /**默認檢查鏈*/ private static DefaultCheckChain checkChain ; /**過濾鏈路表配置*/ static{ checkChain = new DefaultCheckChain(); //參數檢查器 ParamCheckWapper selectParamCheck = new ParamCheckWapper(new SelectParamCheck(),"SelectParamCheck"); ParamCheckWapper groupParamCheck = new ParamCheckWapper(new GroupbyParamCheck(), "groupParamCheck"); ParamCheckWapper conditionParamCheck = new ParamCheckWapper(new ConditionParamCheck(), "conditionParamCheck"); ParamCheckWapper orderbyParamCheck = new ParamCheckWapper(new OrderbyParamCheck(), "orderbyParamCheck"); //參數鏈表增長過濾類 checkChain.addCheck(selectParamCheck); checkChain.addCheck(groupParamCheck); checkChain.addCheck(conditionParamCheck); checkChain.addCheck(orderbyParamCheck); } /** * 參數校驗 */ public void doCheck(Param param) throws Exception { checkChain.doCheck(param); }
以上,就是職責鏈路模式的簡單使用,能夠經過泛型進行代碼剝離,後續涉及到鏈式校驗的時候就能夠經過限制參數進行多樣使用。下降代碼的耦合度;
至此,職責鏈路設計模式的介紹就結束了;