<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      聊一聊責任鏈模式

      將一堆“事情”串聯在一起,有序執行,就叫責任鏈

      一、概述

      責任鏈模式(Chain of Responsibility Pattern)是將鏈中每一個節點看作是一個對象,每個節點處理的請求均不同,且內部自動維護一個下一節點對象。當一個請求從鏈式的首端發出時,會沿著鏈的路徑依次傳遞給每一個節點對象,直至有對象處理這個請求為止,屬于行為型模式。
      下面放一張足球比賽的圖,通過層層傳遞,最終射門。通過這張圖,可以更好的理解責任鏈模式。

      二、入門案例

      2.1 類圖

      2.2 基礎類介紹

      抽象接口RequestHandler

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 13:41
       * @description
       */
      public interface RequestHandler {
      
          void doHandler(String req);
      }
      

      抽象類BaseRequestHandler

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 13:45
       * @description
       */
      public abstract class BaseRequestHandler implements RequestHandler {
      
          protected RequestHandler next;
      
          public void next(RequestHandler next) {
              this.next = next;
          }
      }
      

      具體處理類AHandler

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 14:00
       * @description
       */
      public class AHandler extends BaseRequestHandler {
      
          @Override
          public void doHandler(String req) {
              // 處理自己的業務邏輯
              System.out.println("A中處理自己的邏輯");
              // 傳遞給下個類(若鏈路中還有下個處理類)
              if (next != null) {
                  next.doHandler(req);
              }
          }
      }
      
      

      當然還有具體的處理類B、C等等,這里不展開贅述。
      使用類Client

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 14:06
       * @description
       */
      public class Client {
          public static void main(String[] args) {
              BaseRequestHandler a = new AHandler();
              BaseRequestHandler b = new BHandler();
              BaseRequestHandler c = new CHandler();
              a.next(b);
              b.next(c);
              a.doHandler("鏈路待處理的數據");
          }
      }
      

      2.3 處理流程圖

      三、應用場景

      3.1 場景舉例

      場景一

      前兩年,在一家金融公司待過一段時間,其中就有一個業務場景:一筆訂單進來,會先在后臺通過初審人員進行審批,初審不通過,訂單流程結束。初審通過以后,會轉給終審人員進行審批,不通過,流程結束;通過,流轉到下個業務場景。
      對于這塊業務代碼,之前一代目是一個叫知了的同事,他擼起袖子就是干,一套if-else干到底。后來,技術老大CodeReview,點名要求改掉這塊。于是乎,想到用用設計模式吧,然后就噼里啪啦一頓改。(當然,比較復雜的情況,還是可以用工作流來處理這個場景,當時礙于時間成本,也就放棄了)。

      場景二

      上家公司對接甲方爸爸的時候,對方會調用我們接口,將數據同步過來。同樣,我們需要將處理好的數據,傳給他們。由于雙方傳輸數據都是加密傳輸,所以在接受他們數據之前,需要對數據進行解密,驗簽,參數校驗等操作。同樣,我們給他們傳數據也需要進行加簽,加密操作。

      具體案例

      話不多說,對于場景二,我來放一些偽代碼,跟大家一起探討下。
      1、一切從注解開始,我這里自定義了一個注解@Duty,這個注解有spring的@Component注解,也就是標記了這個自定義注解的類,都是交給spring的bean容器去管理。
      注解中,有兩個屬性:1.type,定義相同的type類型的bean,會被放到一個責任鏈集合中。2.order,同一個責任鏈集合中,bean的排序,數值越小,會放到鏈路最先的位置,優先處理。

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 16:11
       * @description
       */
      @Target({ElementType.TYPE})
      @Retention(RetentionPolicy.RUNTIME)
      @Documented
      @Inherited
      @Service
      public @interface Duty {
          /**
           * 標記具體業務場景
           * @return
           */
          String type() default "";
      
          /**
           * 排序:數值越小,排序越前
           * @return
           */
          int order() default 0;
      }
      

      2、定義一個頂層的抽象接口IHandler,傳入2個泛型參數,供后續自定義。

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 15:31
       * @description 責任鏈頂層抽象類
       */
      public interface IHandler<T, R> {
          /**
           * 抽象處理類
           * @param t
           * @return
           */
          R handle(T t);
      }
      

      3、定義一個責任鏈bean的管理類HandleChainManager,用來存放不同業務下的責任鏈路集合。在該類中,有一個Map和兩個方法。

      1. handleMap:這個map會存放責任鏈路中,具體的執行類,key是注解@Duty中定義的type值,value是標記了@Duty注解的bean集合,也就是具體的執行類集合。
      2. setHandleMap:傳入具體執行bean的集合,存放在map中。
      3. executeHandle:從map中找到具體的執行bean集合,并依次執行。
      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 16:00
       * @description 責任鏈管理類
       */
      public class HandleChainManager {
          /**
           * 存放責任鏈路上的具體處理類
           * k-具體業務場景名稱
           * v-具體業務場景下的責任鏈路集合
           */
          private Map<String, List<IHandler>> handleMap;
      
          /**
           * 存放系統中責任鏈具體處理類
           * @param handlerList
           */
          public void setHandleMap(List<IHandler> handlerList) {
              handleMap = handlerList
                      .stream()
                      .sorted(Comparator.comparingInt(h -> AnnotationUtils.findAnnotation(h.getClass(), Duty.class).order()))
                      .collect(Collectors.groupingBy(handler -> AnnotationUtils.findAnnotation(handler.getClass(), Duty.class).type()));
          }
      
          /**
           * 執行具體業務場景中的責任鏈集合
           * @param type 對應@Duty注解中的type,可以定義為具體業務場景
           * @param t 被執行的參數
           */
          public <T, R> R executeHandle(String type, T t) {
              List<IHandler> handlers = handleMap.get(type);
              R r = null;
              if (CollectionUtil.isNotEmpty(handlers)) {
                  for (IHandler<T, R> handler : handlers) {
                     r = handler.handle(t);
                  }
              }
              return r;
          }
      }
      

      4、定義一個配置類PatternConfiguration,用于裝配上面的責任鏈管理器HandleChainManager。

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 15:35
       * @description 設計模式配置類
       */
      @Configuration
      public class PatternConfiguration {
      
          @Bean
          public HandleChainManager handlerChainExecute(List<IHandler> handlers) {
              HandleChainManager handleChainManager = new HandleChainManager();
              handleChainManager.setHandleMap(handlers);
              return handleChainManager;
          }
      
      }
      

      5、具體的處理類:SignChainHandler、EncryptionChainHandler、RequestChainHandler,這里我以SignChainHandler為例。
      在具體處理類上標記自定義注解@Duty,該類會被注入到bean容器中,實現IHandler接口,只需關心自己的handle方法,處理具體的業務邏輯。

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/10/25 15:31
       * @description 加簽類
       */
      @Duty(type = BusinessConstants.REQUEST, order = 1)
      public class SignChainHandler implements IHandler<String, String> {
          /**
           * 處理加簽邏輯
           * @param s
           * @return
           */
          @Override
          public String handle(String s) {
              // 加簽邏輯
              System.out.println("甲方爸爸要求加簽");
              return "加簽";
          }
      }
      

      6、具體怎么調用?這里我寫了個測試controller直接調用,具體如下:

      /**
       * @author 往事如風
       * @version 1.0
       * @date 2022/9/6 17:32
       * @description
       */
      @RestController
      @Slf4j
      public class TestController {
      
          @Resource
          private HandleChainManager handleChainManager;
      
          @PostMapping("/send")
          public String duty(@RequestBody String requestBody) {
              String response = handleChainManager.executeHandle(BusinessConstants.REQUEST, requestBody);
              return response;
          }
      }
      

      7、執行結果,會按照注解中標記的order依次執行。

      至此,完工。又可以開心的擼代碼了,然后在具體的執行類中,又是一頓if-else。。。

      四、源碼中運用

      4.1Mybatis源碼中的運用

      Mybatis中的緩存接口Cache,cache作為一個緩存接口,最主要的功能就是添加和獲取緩存的功能,作為接口它有11個實現類,分別實現不同的功能,下面是接口源碼和實現類。

      package org.apache.ibatis.cache;
      
      import java.util.concurrent.locks.ReadWriteLock;
      
      public interface Cache {
          String getId();
      
          void putObject(Object var1, Object var2);
      
          Object getObject(Object var1);
      
          Object removeObject(Object var1);
      
          void clear();
      
          int getSize();
      
          default ReadWriteLock getReadWriteLock() {
              return null;
          }
      }
      

      下面,我們來看下其中一個子類LoggingCache的源碼。主要看他的putObject方法和getObject方法,它在方法中直接傳給下一個實現去執行。這個實現類其實是為了在獲取緩存的時候打印緩存的命中率的。

      public class LoggingCache implements Cache {
          private final Log log;
          private final Cache delegate;
          protected int requests = 0;
          protected int hits = 0;
      
          public LoggingCache(Cache delegate) {
              this.delegate = delegate;
              this.log = LogFactory.getLog(this.getId());
          }
      
          // ...
          public void putObject(Object key, Object object) {
              this.delegate.putObject(key, object);
          }
      
          public Object getObject(Object key) {
              ++this.requests;
              Object value = this.delegate.getObject(key);
              if (value != null) {
                  ++this.hits;
              }
      
              if (this.log.isDebugEnabled()) {
                  this.log.debug("Cache Hit Ratio [" + this.getId() + "]: " + this.getHitRatio());
              }
      
              return value;
          }
          // ...
      }
      

      最后,經過Cache接口各種實現類的處理,最終會到達PerpetualCache這個實現類。與之前的處理類不同的是,這個類中有一個map,在map中做存取,也就是說,最終緩存還是會保存在map中的。

      public class PerpetualCache implements Cache {
          private final String id;
          private final Map<Object, Object> cache = new HashMap();
      
          public PerpetualCache(String id) {
              this.id = id;
          }
      
      	// ...
      
          public void putObject(Object key, Object value) {
              this.cache.put(key, value);
          }
      
          public Object getObject(Object key) {
              return this.cache.get(key);
          }
      	// ...
      
      }
      

      4.2spring源碼中的運用

      4.2.1DispatcherServlet類

      DispatcherServlet 核心方法 doDispatch。HandlerExecutionChain只是維護HandlerInterceptor的集合,可以向其中注冊相應的攔截器,本身不直接處理請求,將請求分配給責任鏈上注冊處理器執行,降低職責鏈本身與處理邏輯之間的耦合程度。

      protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
      		HttpServletRequest processedRequest = request;
      		HandlerExecutionChain mappedHandler = null;
      		boolean multipartRequestParsed = false;
      		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      		try {
      			ModelAndView mv = null;
      			Exception dispatchException = null;
      			try {
      				processedRequest = checkMultipart(request);
      				multipartRequestParsed = (processedRequest != request);
      				// Determine handler for the current request.
      				mappedHandler = getHandler(processedRequest);
      				if (mappedHandler == null) {
      					noHandlerFound(processedRequest, response);
      					return;
      				}
      				// Determine handler adapter for the current request.
      				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
      				// Process last-modified header, if supported by the handler.
      				String method = request.getMethod();
      				boolean isGet = "GET".equals(method);
      				if (isGet || "HEAD".equals(method)) {
      					long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
      					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
      						return;
      					}
      				}
      				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
      					return;
      				}
      				// Actually invoke the handler.
      				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      				if (asyncManager.isConcurrentHandlingStarted()) {
      					return;
      				}
      				applyDefaultViewName(processedRequest, mv);
      				mappedHandler.applyPostHandle(processedRequest, response, mv);
      			}
      			catch (Exception ex) {
      				dispatchException = ex;
      			}
      			catch (Throwable err) {
      				// As of 4.3, we're processing Errors thrown from handler methods as well,
      				// making them available for @ExceptionHandler methods and other scenarios.
      				dispatchException = new NestedServletException("Handler dispatch failed", err);
      			}
      			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
      		}
      		catch (Exception ex) {
      			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
      		}
      		catch (Throwable err) {
      			triggerAfterCompletion(processedRequest, response, mappedHandler,
      					new NestedServletException("Handler processing failed", err));
      		}
      		finally {
      			if (asyncManager.isConcurrentHandlingStarted()) {
      				// Instead of postHandle and afterCompletion
      				if (mappedHandler != null) {
      					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
      				}
      			}
      			else {
      				// Clean up any resources used by a multipart request.
      				if (multipartRequestParsed) {
      					cleanupMultipart(processedRequest);
      				}
      			}
      		}
      	}
      

      4.2.2HandlerExecutionChain類

      這里分析的幾個方法,都是從DispatcherServlet類的doDispatch方法中請求的。

      • 獲取攔截器,執行preHandle方法
      boolean applyPreHandle(HttpServletRequest request, 
                             HttpServletResponse response) throws Exception {
          HandlerInterceptor[] interceptors = this.getInterceptors();
          if (!ObjectUtils.isEmpty(interceptors)) {
              for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
                  HandlerInterceptor interceptor = interceptors[i];
                  if (!interceptor.preHandle(request, response, this.handler)) {
                      this.triggerAfterCompletion(request, response, (Exception)null);
                      return false;
                  }
              }
          }
          return true;
      }
      
      • 在applyPreHandle方法中,執行triggerAfterCompletion方法
      void triggerAfterCompletion(HttpServletRequest request, 
                                  HttpServletResponse response, Exception ex) throws Exception {
          HandlerInterceptor[] interceptors = this.getInterceptors();
          if (!ObjectUtils.isEmpty(interceptors)) {
              for(int i = this.interceptorIndex; i >= 0; --i) {
                  HandlerInterceptor interceptor = interceptors[i];
                  try {
                      interceptor.afterCompletion(request, response, this.handler, ex);
                  } catch (Throwable var8) {
                      logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
                  }
              }
          }
      }
      
      • 獲取攔截器,執行applyPostHandle方法
      void applyPostHandle(HttpServletRequest request, 
                           HttpServletResponse response, ModelAndView mv) 
                           throws Exception {
          HandlerInterceptor[] interceptors = this.getInterceptors();
          if (!ObjectUtils.isEmpty(interceptors)) {
              for(int i = interceptors.length - 1; i >= 0; --i) {
                  HandlerInterceptor interceptor = interceptors[i];
                  interceptor.postHandle(request, response, this.handler, mv);
              }
          }
      }
      

      五、總結

      5.1 優點

      1. 將請求與處理解耦。
      2. 請求處理者(節點對象)只需要關注自己感興趣的請求進行處理即可,對于不感興趣的請求,轉發給下一個節點。
      3. 具備鏈式傳遞處理請求功能,請求發送者無需知曉鏈路結構,只需等待請求處理結果。
      4. 鏈路結構靈活,可以通過改變鏈路的結構動態的新增或刪減責任。
      5. 易于擴展新的請求處理類(節點),符合開閉原則

      5.2 缺點

      1. 責任鏈太長或者處理時間過長,會影響整體性能。
      2. 如果節點對象存在循環引用時,會造成死循環,導致系統崩潰。

      六、參考源碼

      編程文檔:
      https://gitee.com/cicadasmile/butte-java-note
      
      應用倉庫:
      https://gitee.com/cicadasmile/butte-flyer-parent
      
      posted @ 2022-11-01 08:39  七號樓  閱讀(904)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 成人网站免费在线观看| 美女扒开尿口让男人桶| 亚洲成人高清av在线| 美女黄网站人色视频免费国产| 亚洲欧洲一区二区天堂久久| 欧美牲交a欧美牲交aⅴ图片| 国产毛片基地| 国产破外女出血视频| 国产亚洲999精品AA片在线爽| 91中文字幕一区在线| 久激情内射婷内射蜜桃| 免费国产高清在线精品一区| 亚洲国产精品成人综合色在| 无码日韩精品91超碰| 午夜福利看片在线观看| 国产精品色一区二区三区| 福利一区二区视频在线| 亚洲一区二区中文av| 伊人av超碰伊人久久久| 久久SE精品一区精品二区| 女人裸体性做爰视频| 成人啪啪高潮不断观看| 亚洲国产精品成人综合色在| 亚洲成人av综合一区| 中文字幕国产精品av| 疯狂添女人下部视频免费| 一本一道av无码中文字幕麻豆 | 一区二区不卡国产精品| 亚洲国产成人精品女久久| 国产成人无码免费视频在线 | 国产精品一区二区传媒蜜臀| 国产成人无码A区在线观| 亚洲成色精品一二三区| 国产福利精品一区二区| 在线视频观看| 中文字幕国产日韩精品| 狠狠躁夜夜躁人人爽天天5| 亚洲熟女片嫩草影院| 免费超爽大片黄| 亚洲熟女乱一区二区三区| 99久9在线视频 | 传媒|