1.什么是责任链设计模式
客户端发起一个请求、链上面所有的对象都有机会处理该请求
2.责任链角色
抽象处理者角色(Handler)
具体处理者角色(ConcreateHandler)
3.应用场景
filter过滤器中doFiler方法
4.通过工厂实现责任链模式
链接:https://pan.baidu.com/s/1QgyEWDCotAteOVxh2-6ErQ
提取码:jtim
1)pom依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
</dependencies>
2)抽象处理者handler
public abstract class GatewayHandler {
private GatewayHandler nextGatewayHandler;
public void setNextGatewayHandler(GatewayHandler nextGatewayHandler) {
this.nextGatewayHandler = nextGatewayHandler;
}
/**
* 实现的handler 处理方案 强制必须实现
*/
public abstract void service();
/**
* 执行下一个handler
*/
public void nextService() {
if (nextGatewayHandler != null) {
nextGatewayHandler.service();// 指向下一关黑名单
}
}
}
3)具体处理者ConcreateHandler
import com.demo.handler.GatewayHandler;
import org.springframework.stereotype.Component;
@Component
public class CurrentLimitHandler extends GatewayHandler {
public void service() {
System.out.println("第一关 API接口限流操作.....");
// 指向下一关
nextService();
}
}
import com.demo.handler.GatewayHandler;
import org.springframework.stereotype.Component;
@Component
public class BlacklistHandler extends GatewayHandler {
public void service() {
System.out.println("第二关 黑名单拦截.......");
nextService();
}
}
import com.demo.handler.GatewayHandler;
import org.springframework.stereotype.Component;
@Component
public class ConversationHandler extends GatewayHandler {
public void service() {
System.out.println("第三关 用户的会话信息拦截.......");
}
}
4)工厂
import com.demo.handler.GatewayHandler;
import com.demo.handler.impl.BlacklistHandler;
import com.demo.handler.impl.ConversationHandler;
import com.demo.handler.impl.CurrentLimitHandler;
public class FactoryHandler {
/**
* 使用工厂模式封装Handler责任链
*/
public static GatewayHandler getGatewayHandler() {
//第一关
CurrentLimitHandler currentLimitHandler = new CurrentLimitHandler();
//第二关
BlacklistHandler blacklistHandler = new BlacklistHandler();
currentLimitHandler.setNextGatewayHandler(blacklistHandler);
//第三关
ConversationHandler conversationHandler = new ConversationHandler();
blacklistHandler.setNextGatewayHandler(conversationHandler);
return currentLimitHandler;
}
}
5)控制层
import com.demo.factory.FactoryHandler;
import com.demo.handler.GatewayHandler;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class HandlerController {
@RequestMapping("/client")
public String client() {
GatewayHandler gatewayHandler = FactoryHandler.getGatewayHandler();
gatewayHandler.service();
return "success";
}
}
6)启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AppHandler {
public static void main(String[] args) {
SpringApplication.run(AppHandler.class);
}
}
7)测试
5.通过数据库实现责任链模式
链接:https://pan.baidu.com/s/1-lzzEC96Xxdc4pMYZptpVw
提取码:7mfi
1)数据库
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 50727
Source Host : localhost:3306
Source Schema : design_pattern
Target Server Type : MySQL
Target Server Version : 50727
File Encoding : 65001
Date: 21/02/2022 13:28:11
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for gateway_handler
-- ----------------------------
DROP TABLE IF EXISTS `gateway_handler`;
CREATE TABLE `gateway_handler` (
`handler_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'handler名称',
`handler_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT 'handler主键id',
`prev_handler_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '第一个handler',
`next_handler_id` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '下一个handler',
`id` int(11) NOT NULL AUTO_INCREMENT,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of gateway_handler
-- ----------------------------
INSERT INTO `gateway_handler` VALUES ('API接口限流操作', 'currentLimitHandler', NULL, 'blacklistHandler', 1);
INSERT INTO `gateway_handler` VALUES ('黑名单拦截', 'blacklistHandler', 'currentLimitHandler', 'conversationHandler', 2);
INSERT INTO `gateway_handler` VALUES ('用户的会话信息拦截', 'conversationHandler', 'blacklistHandler', NULL, 3);
SET FOREIGN_KEY_CHECKS = 1;
2)pom依赖
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.11.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<!-- sprinboot web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.10</version>
</dependency>
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
<version>2.6</version>
</dependency>
<!-- mysql 依赖 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
3)yml
###服务启动端口号
server:
port: 8080
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/design_pattern?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
####打印MyBatias日志
logging:
level:
### 开发环境使用DEBUG 生产环境info或者error
com.demo.mapper: DEBUG
4)entity
import lombok.Data;
import java.io.Serializable;
@Data
public class GatewayHandlerEntity implements Serializable, Cloneable {
/**
* 主键ID
*/
private Integer id;
/**
* handler名称
*/
private String handlerName;
/**
* handler主键id
*/
private String handlerId;
/**
* 下一个handler
*/
private String nextHandlerId;
}
5)mapper
import com.demo.entity.GatewayHandlerEntity;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface GatewayHandlerMapper {
/**
* 获取第一个GatewayHandler
*
* @return
*/
@Select("SELECT handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid FROM gateway_handler WHERE prev_handler_id is null;")
GatewayHandlerEntity getFirstGatewayHandler();
/**
* 根据handler_id 获取
* */
@Select("SELECT handler_name AS handlerName,handler_id AS handlerid ,prev_handler_id AS prevhandlerid ,next_handler_id AS nexthandlerid FROM gateway_handler WHERE handler_id=#{handlerId}")
GatewayHandlerEntity getByHandler(String handlerId);
}
6)抽象处理者handler
public abstract class GatewayHandler {
private GatewayHandler nextGatewayHandler;
public void setNextGatewayHandler(GatewayHandler nextGatewayHandler) {
this.nextGatewayHandler = nextGatewayHandler;
}
/**
* 实现的handler 处理方案 强制必须实现
*/
public abstract void service();
/**
* 执行下一个handler
*/
public void nextService() {
if (nextGatewayHandler != null) {
nextGatewayHandler.service();// 指向下一关黑名单
}
}
}
7)具体处理者ConcreateHandler
import com.demo.handler.GatewayHandler;
import org.springframework.stereotype.Component;
@Component
public class CurrentLimitHandler extends GatewayHandler {
public void service() {
System.out.println("第一关 API接口限流操作.....");
// 指向下一关
nextService();
}
}
import com.demo.handler.GatewayHandler;
import org.springframework.stereotype.Component;
@Component
public class BlacklistHandler extends GatewayHandler {
public void service() {
System.out.println("第二关 黑名单拦截.......");
nextService();
}
}
import com.demo.handler.GatewayHandler;
import org.springframework.stereotype.Component;
@Component
public class ConversationHandler extends GatewayHandler {
public void service() {
System.out.println("第三关 用户的会话信息拦截.......");
}
}
8)utils
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
/**
* 获取applicationContext
*/
public 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返回指定的Bean
*/
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
9)service
import com.demo.entity.GatewayHandlerEntity;
import com.demo.handler.GatewayHandler;
import com.demo.mapper.GatewayHandlerMapper;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import com.demo.utils.SpringUtils;
import javax.annotation.Resource;
@Service
public class GatewayHandlerService {
@Resource
private GatewayHandlerMapper gatewayHandlerMapper;
private GatewayHandler firstGatewayHandler;
/**
* 获取数据库第一个handeler封装
* @return
*/
public GatewayHandler getFirstGatewayHandler() {
if (firstGatewayHandler != null) {
return firstGatewayHandler;
}
// 1.从数据库获取第一个handler
GatewayHandlerEntity firstGatewayHandlerEntity = gatewayHandlerMapper.getFirstGatewayHandler();
if (firstGatewayHandlerEntity == null) {
return null;
}
String handlerId = firstGatewayHandlerEntity.getHandlerId();
GatewayHandler firstGatewayHandler = SpringUtils.getBean(handlerId, GatewayHandler.class);
// 2.获取下一个handler容器beanid
String nextHandlerId = firstGatewayHandlerEntity.getNextHandlerId();
// 3. 记录当前循环hanlder对象
GatewayHandler tempGatewayHandler = firstGatewayHandler;
while (StringUtils.isNotEmpty(nextHandlerId)) {
// 4.从springboot容器获取下一个handerl对象
GatewayHandler nextGatewayHandler = SpringUtils.getBean(nextHandlerId, GatewayHandler.class);
tempGatewayHandler.setNextGatewayHandler(nextGatewayHandler);
// 5.设置下一个nextHandlerId
GatewayHandlerEntity nextGatewayHandlerEntity = gatewayHandlerMapper.getByHandler(nextHandlerId);
if (nextGatewayHandlerEntity == null) {
break;
}
nextHandlerId = nextGatewayHandlerEntity.getNextHandlerId();
tempGatewayHandler = nextGatewayHandler;
}
this.firstGatewayHandler = firstGatewayHandler;
return firstGatewayHandler;
}
}
10)controller
import com.demo.handler.GatewayHandler;
import com.demo.service.GatewayHandlerService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
public class HandlerController {
@Resource
private GatewayHandlerService gatewayHandlerService;
@RequestMapping("/client")
public String client() {
GatewayHandler firstGatewayHandler = gatewayHandlerService.getFirstGatewayHandler();
firstGatewayHandler.service();
return "success";
}
}
11)测试