將一堆「事情」串聯在一起,有序執行,就叫責任鏈
責任鏈模式(Chain of Responsibility Pattern)是將鏈中每一個節點看作是一個物件,每個節點處理的請求均不同,且內部自動維護一個下一節點物件。當一個請求從鏈式的首端發出時,會沿著鏈的路徑依次傳遞給每一個節點物件,直至有物件處理這個請求為止,屬於行為型模式。
下面放一張足球比賽的圖,通過層層傳遞,最終射門。通過這張圖,可以更好的理解責任鏈模式。
抽象介面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("鏈路待處理的資料");
}
}
前兩年,在一家金融公司待過一段時間,其中就有一個業務場景:一筆訂單進來,會先在後臺通過初審人員進行審批,初審不通過,訂單流程結束。初審通過以後,會轉給終審人員進行審批,不通過,流程結束;通過,流轉到下個業務場景。
對於這塊業務程式碼,之前一代目是一個叫知了的同事,他擼起袖子就是幹,一套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和兩個方法。
@Duty
中定義的type值,value是標記了@Duty
註解的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。。。
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);
}
// ...
}
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);
}
}
}
}
這裡分析的幾個方法,都是從DispatcherServlet類的doDispatch方法中請求的。
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;
}
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);
}
}
}
}
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);
}
}
}
程式設計檔案:
https://gitee.com/cicadasmile/butte-java-note
應用倉庫:
https://gitee.com/cicadasmile/butte-flyer-parent