精讲23种设计模式-基于责任链模式~构建企业级风控系统
文章目錄
- 一、責任鏈
- 1. 責任鏈基本概念
- 2. 定義
- 3. 關鍵要點
- 4. 責任鏈模式優缺點
- 5. 責任鏈模式類結構圖
- 6. 網關權限控制責任鏈模式
- 二、構建企業級風控系統
- 2.1. 定義公共抽象任務
- 2.2. (失信名單)校驗處理類
- 2.3. (信用卡)逾期處理類
- 2.4. (螞蟻信用積分)處理類
- 2.5. 責任鏈工廠(第一種)
- 三、模式重構升級
- 3.1. mysql表結構
- 3.2. 任務實體
- 3.3. 責任鏈接口
- 3.4. Spring上下文工具類
- 3.5. 責任鏈處理類
- 3.6. 測試入口
- 3.7. 掃描配置
- 3.8. yml配置
- 3.9. maven
- 3.10. 開源項目
一、責任鏈
1. 責任鏈基本概念
客戶端發出一個請求,鏈上的對象都有機會來處理這一請求,而客戶端不需要知道誰是具體的處理對象。這樣就實現了請求者和接受者之間的解耦,并且在客戶端可以實現動態的組合職責鏈。使編程更有靈活性。
2. 定義
使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有對象處理它為止。其過程實際上是一個遞歸調用。
3. 關鍵要點
1、有多個對象共同對一個任務進行處理。
2、這些對象使用鏈式存儲結構,形成一個鏈,每個對象知道自己的下一個對象。
3、一個對象對任務進行處理,可以添加一些操作后將對象傳遞個下一個任務。也可以在此對象上結束任務的處理,并結束任務。
4、客戶端負責組裝鏈式結構,但是客戶端不需要關心最終是誰來處理了任務。
多個對象指的是什么意思?
4. 責任鏈模式優缺點
優點:
職責鏈模式的最主要功能就是:動態組合,請求者和接受者解耦。
請求者和接受者松散耦合:請求者不需要知道接受者,也不需要知道如何處理。每個職責對象只負責自己的職責范圍,其他的交給后繼者。各個組件間完全解耦。
動態組合職責:職責鏈模式會把功能分散到單獨的職責對象中,然后在使用時動態的組合形成鏈,從而可以靈活的分配職責對象,也可以靈活的添加改變對象職責。
缺點:
產生很多細粒度的對象:因為功能處理都分散到了單獨的職責對象中,每個對象功能單一,要把整個流程處理完,需要很多的職責對象,會產生大量的細粒度職責對象。
不一定能處理:每個職責對象都只負責自己的部分,這樣就可以出現某個請求,即使把整個鏈走完,都沒有職責對象處理它。這就需要提供默認處理,并且注意構造鏈的有效性。
5. 責任鏈模式類結構圖
1.抽象處理者(Handler)角色:定義出一個處理請求的接口。如果需要,接口可以定義 出一個方法以設定和返回對下家的引用。這個角色通常由一個Java抽象類或者Java接口實現。上圖中Handler類的聚合關系給出了具體子類對下家的引用,抽象方法handleRequest()規范了子類處理請求的操作。
2.具體處理者(ConcreteHandler)角色:具體處理者接到請求后,可以選擇將請求處理掉,或者將請求傳給下家。由于具體處理者持有對下家的引用,因此,如果需要,具體處理者可以訪問下家
責任鏈模式應用場景
比如:在Java過濾器中客戶端發送請求到服務器端,過濾會經過參數過濾、session過濾、表單過濾、隱藏過濾、檢測請求頭過濾
6. 網關權限控制責任鏈模式
在網關作為微服務程序的入口,攔截客戶端所有的請求實現權限控制 ,比如先判斷Api接口限流、黑名單、用戶會話、參數過濾。
Api接口限流→黑名單攔截→用戶會話→參數過濾
二、構建企業級風控系統
2.1. 定義公共抽象任務
package com.gblfy.mapper;/*** 公共抽象任務** @author gblfy* @date 2022-03-14*/ public abstract class GatewayHandler {/*** 處理業務邏輯*/public abstract void doService();protected GatewayHandler nextGatewayHandler;public GatewayHandler() {}public GatewayHandler(GatewayHandler nextGatewayHandler) {this.nextGatewayHandler = nextGatewayHandler;}//責任鏈工廠時用到此構造方法public void setNextGatewayHandler(GatewayHandler nextGatewayHandler) {this.nextGatewayHandler = nextGatewayHandler;} }2.2. (失信名單)校驗處理類
package com.gblfy.service;import com.gblfy.mapper.GatewayHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;/*** (失信名單)校驗** @author gblfy* @date 2022-03-14*/ @Slf4j @Service public class DishonestListHandler extends GatewayHandler {public DishonestListHandler() {}public DishonestListHandler(GatewayHandler nextGatewayHandler) {super(nextGatewayHandler);}@Overridepublic void doService() {log.info("---------------------(失信名單)校驗處理邏輯---------------------");nextGatewayHandler.doService();} }2.3. (信用卡)逾期處理類
package com.gblfy.service;import com.gblfy.mapper.GatewayHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;/*** (信用卡)逾期** @author gblfy* @date 2022-03-14*/ @Slf4j @Service public class CreditCardOverdueHandler extends GatewayHandler {public CreditCardOverdueHandler() {}@Overridepublic void doService() {log.info("---------------------(信用卡)逾期處理邏輯---------------------");nextGatewayHandler.doService();}public CreditCardOverdueHandler(GatewayHandler nextGatewayHandler) {super(nextGatewayHandler);} }2.4. (螞蟻信用積分)處理類
package com.gblfy.service;import com.gblfy.mapper.GatewayHandler; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service;/*** (螞蟻信用積分)** @author gblfy* @date 2022-03-14*/ @Slf4j @Service public class CreditPointsHandler extends GatewayHandler {public CreditPointsHandler() {}@Overridepublic void doService() {log.info("---------------------(螞蟻信用積分)處理邏輯--->700分------------------");}public CreditPointsHandler(GatewayHandler nextGatewayHandler) {super(nextGatewayHandler);} }2.5. 責任鏈工廠(第一種)
package com.gblfy.factory;import com.gblfy.service.CreditCardOverdueHandler; import com.gblfy.service.DishonestListHandler; import com.gblfy.service.CreditPointsHandler; import org.springframework.stereotype.Component;/*** 責任鏈工廠(第一種)** @author gblfy* @date 2022-03-14*/ @Component public class FactoryHandler {public DishonestListHandler getCurrentLimitHandler() {DishonestListHandler dishonestListHandler = new DishonestListHandler();CreditCardOverdueHandler creditCardOverdueHandler = new CreditCardOverdueHandler();//失信名單指向->>用卡是否逾期校驗dishonestListHandler.setNextGatewayHandler(creditCardOverdueHandler);//信用卡是否逾期校驗指向->>螞蟻信用積分是否大于700分creditCardOverdueHandler.setNextGatewayHandler(new CreditPointsHandler());return dishonestListHandler;}public static void main(String[] args) {new FactoryHandler().getCurrentLimitHandler().doService();} }三、模式重構升級
3.1. mysql表結構
drop database IF EXISTS `design_pattern`; create database `design_pattern`; use `design_pattern`;SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;-- ---------------------------- -- Table structure for gblfy_strategy -- ---------------------------- DROP TABLE IF EXISTS `gateway_handler`; CREATE TABLE `gateway_handler` (`id` int NOT NULL AUTO_INCREMENT COMMENT '主鍵ID',`handler_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT '節點名稱',`handler_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '節點主鍵id',`prev_handler_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '上一個節點',`next_handler_id` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '下一個節點',PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 19 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '權限表' ROW_FORMAT = DYNAMIC;-- ---------------------------- -- Records of gateway_handler -- ---------------------------- INSERT INTO `gateway_handler` VALUES (16, '失信名單校驗', 'dishonestListHandler', NULL, 'creditCardOverdueHandler'); INSERT INTO `gateway_handler` VALUES (17, '信用卡是否逾期', 'creditCardOverdueHandler', 'dishonestListHandler', 'creditPointsHandler'); INSERT INTO `gateway_handler` VALUES (18, '螞蟻積分是否大于700分', 'creditPointsHandler', 'creditCardOverdueHandler', NULL);3.2. 任務實體
package com.gblfy.entity;import com.baomidou.mybatisplus.annotation.*; import lombok.Data;@Data @TableName("gateway_handler") public class GatewayHandlerEntity {// 策略配置主鍵@TableId(value = "id", type = IdType.ASSIGN_ID)private Long id;//節點名稱(Api接口限流、黑名單攔截、token驗證)@TableField("handler_name")private String handlerName;//節點ID@TableField("handler_id")private String handlerId;//上一個節點@TableField("prev_handler_id")private String prevHandlerId;//下一個節點@TableField("next_handler_id")private String nextHandlerId; }3.3. 責任鏈接口
package com.gblfy.mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.gblfy.entity.GatewayHandlerEntity;/*** 責任鏈接口** @author gblfy* @date 2022-03-13*/ public interface GatewayHandlerMapper extends BaseMapper<GatewayHandlerEntity> { }3.4. Spring上下文工具類
package com.gblfy.utils;import org.springframework.beans.BeansException; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.stereotype.Component;/*** 獲取Spring上下文工具類** @author gblfy* @date 2022-03-13*/ @Component public class SpringContextUtils implements ApplicationContextAware {private static ApplicationContext applicationContext;@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {SpringContextUtils.applicationContext = applicationContext;}//獲取applicationContextpublic static ApplicationContext getApplicationContext() {return applicationContext;}//通過name獲取 Bean.public static Object getBean(String name) {return getApplicationContext().getBean(name);}//通過class獲取Bean.public static <T> T getBean(Class<T> clazz) {return getApplicationContext().getBean(clazz);}//通過name,以及Clazz返回指定的Beanpublic static <T> T getBean(String name, Class<T> clazz) {return getApplicationContext().getBean(name, clazz);}}3.5. 責任鏈處理類
package com.gblfy.factory;import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.gblfy.entity.GatewayHandlerEntity; import com.gblfy.mapper.GatewayHandler; import com.gblfy.mapper.GatewayHandlerMapper; import com.gblfy.utils.SpringContextUtils; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component;/*** 責任鏈處理類(數據庫方案)** @author gblfy* @date 2022-03-14*/ @Slf4j @Component public class DbHandle {@Autowiredprivate GatewayHandlerMapper gatewayHandlerMapper;private GatewayHandler firstGatewayHandler;//當數據庫審批節點發生變化時,需要將firstGatewayHandler設置為nullpublic GatewayHandler getFirstGatewayHandler() {if (firstGatewayHandler != null) {return firstGatewayHandler;}// 1.查詢頭節點handle beanid 查詢prev_handler_id為空的情況下,標明為頭節點GatewayHandlerEntity gatewayHandlerEntity = gatewayHandlerMapper.selectOne(new QueryWrapper<GatewayHandlerEntity>().lambda().isNull(GatewayHandlerEntity::getPrevHandlerId));if (gatewayHandlerEntity == null) {log.error("很抱歉,您沒有配置頭節點");return null;}// 2.獲取頭節點的handleidString firstHandlerId = gatewayHandlerEntity.getHandlerId();if (StringUtils.isEmpty(firstHandlerId)) {log.error("很抱歉,您沒有配置頭節點");return null;}// 3.從容器中獲取HandlerId對應的對象firstGatewayHandler = SpringContextUtils.getBean(firstHandlerId, GatewayHandler.class);if (firstGatewayHandler == null) {log.error("您的代碼中,沒有配置{}", firstHandlerId + ",的對象");return null;}// 4.能夠成功獲取限流處理器,獲取下一個處理器beanidString nextHandlerId = gatewayHandlerEntity.getNextHandlerId();// 5.定義一個中間變量,解決最后一個對象覆蓋第一個對象的問題->>記錄當前循環的對象GatewayHandler tempGatewayHandler = firstGatewayHandler;// 6.當下一個節點不為空時,開始遞歸獲取while (StringUtils.isNotBlank(nextHandlerId)) {// 7.從spring容器中獲取下一個節點對象GatewayHandler nextgatewayHandler = SpringContextUtils.getBean(nextHandlerId, GatewayHandler.class);if (nextgatewayHandler == null) {break;}GatewayHandlerEntity nextGatewayHandlerEntity = gatewayHandlerMapper.selectOne(new QueryWrapper<GatewayHandlerEntity>().lambda().eq(GatewayHandlerEntity::getHandlerId, nextHandlerId));if (nextGatewayHandlerEntity == null) {break;}nextHandlerId = nextGatewayHandlerEntity.getNextHandlerId();// 8.這是責任鏈關鍵代碼tempGatewayHandler.setNextGatewayHandler(nextgatewayHandler);tempGatewayHandler = nextgatewayHandler;}// 9.為了避免每次都查詢db這里,第一次查詢之后,可以緩存到全局變量中,下次查詢時直接返回this.firstGatewayHandler = firstGatewayHandler;return firstGatewayHandler;} }3.6. 測試入口
package com.gblfy.controller;import com.gblfy.factory.DbHandle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;@RestController public class HandleController {@Autowiredprivate DbHandle dbHandle;@GetMapping("/getHandle")public void getHandle() {dbHandle.getFirstGatewayHandler().doService();} }3.7. 掃描配置
package com.gblfy.config;import org.mybatis.spring.annotation.MapperScan; import org.springframework.context.annotation.Configuration;@Configuration @MapperScan("com.gblfy.mapper") public class MybatisPlusConfig {}3.8. yml配置
server:port: 8080 spring:datasource:username: rootpassword: 123456driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/design_pattern?useUnicode=true&characterEncoding=UTF-8 logging:level:com.gblfy.mapper: DEBUG mybatis-plus:configuration:log-impl:mapper-locations: classpath:mappers/*.xml3.9. maven
<dependencies><!--字符串工具類--><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.12.0</version></dependency><!--數據json處理--><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.79</version></dependency><!--SpringMVC--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--mybatis-plus 持久化--><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.5.1</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>3.10. 開源項目
https://gitee.com/gblfy/design-pattern/tree/duty-chain
總結
以上是生活随笔為你收集整理的精讲23种设计模式-基于责任链模式~构建企业级风控系统的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Docker JFrog Artifac
- 下一篇: js json数据传递传递、json数据