# wanyj-component
**Repository Path**: user_wan/wanyj-component
## Basic Information
- **Project Name**: wanyj-component
- **Description**: 《通用组件中心》动态配置、规则树、责任链、动态限流
- **Primary Language**: Java
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-02-07
- **Last Updated**: 2026-02-07
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Getting Started
- [1. 动态配置中心](#1-动态配置中心)
- [2. 设计模式框架 - 规则树](#2-设计模式框架---规则树)
- [3. 设计模式框架 - 责任链](#3-设计模式框架---责任链)
- [4. 动态限流组件](#4-动态限流组件)
## 1. 动态配置中心
### 1.1. 简介
一个分布式动态配置中心,基于 Redisson 实现,通过发布/订阅模式实现属性值的动态更新
### 1.2 优点
- 保证了分布式场景的数据一致性
- 不需要频繁的从 Redis 中获取数据
### 1.3 使用方法
#### step1: 引入依赖
```xml
cn.wanyj.component
dynamic-config-center-spring-boot-starter
1.0.0
```
#### step2: 配置 yml
```yml
wanyj:
component:
dcc:
system:
spring:
data:
redis:
database:
host:
port:
password:
ssl:
timeout:
connectTimeout:
clientName:
cluster:
nodes:
sentinel:
master:
nodes:
```
对于 Redisson 的配置,可以参考 Redisson 的官方文档:https://redisson.pro/docs/integration-with-spring 按需配置即可
#### step3: 通过注解方式使用
1. 使用字段名作为属性名
```java
@DccConfig("0")
private String t1;
```
2. 使用自定义属性名
```java
@DccConfig("custom:0")
private String t2;
```
#### step4: 配置变更
```java
@Resource
private RTopic dynamicConfigCenterRedisTopic;
dynamicConfigCenterRedisTopic.publish(new AttributeEntity("t1", "1"));
dynamicConfigCenterRedisTopic.publish(new AttributeEntity("custom", "1"));
```
## 2. 设计模式框架 - 规则树
### 2.1. 简介
解耦业务逻辑与流程流转,将特定业务代码封装成节点,动态组装使用
### 2.2 优点
- 避免频繁地编写 if…else 逻辑
- 可以回到已经走过的节点,实现节点复用
### 2.3 使用方法
#### step1: 引入依赖
```xml
cn.wanyj.component
design-pattern-framework
1.0.0
```
#### step2: 根据需求,自定义上下文实体
```java
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DynamicContext {
private int sum;
private Map dataObjects = new HashMap<>();
public void setValue(String key, T value) {
dataObjects.put(key, value);
}
public T getValue(String key) {
return (T) dataObjects.get(key);
}
}
```
#### step3: 自定义抽象类继承`AbstractMultiThreadStrategyRouter`类
```java
public abstract class AbstractXxxSupport extends AbstractMultiThreadStrategyRouter<入参, 上下文实体, 出参> {
}
```
#### step4: 编写各个节点,并继承自定义的抽象类,重写`doApply`和`getNext`方法,如果有数据要加载,重写`multiThread`方法
```java
@Slf4j
@Component
public class Node1 extends AbstractXxxSupport {
@Resource
private ThreadPoolExecutor threadPoolExecutor;
@Resource
private Node2_1 node2_1;
@Resource
private Node2_2 node2_2;
@Override
protected void multiThread(String userId, DynamicContext dynamicContext) {
CompletableFuture mock1 = CompletableFuture.supplyAsync(() -> {
log.info("线程1加载数据");
return new Random().nextBoolean() ? 1 : 2;
}, threadPoolExecutor);
CompletableFuture mock2 = CompletableFuture.supplyAsync(() -> {
log.info("线程2加载数据");
return new Random().nextBoolean() ? 1 : 2;
}, threadPoolExecutor);
CompletableFuture.allOf(mock1, mock2)
.thenRun(() -> {
dynamicContext.setValue("mock1", mock1.join());
dynamicContext.setValue("mock2", mock2.join());
}).join();
}
@Override
protected String doApply(String userId, DynamicContext dynamicContext) {
log.info("[Node1]:{}", userId);
int sum = 3;
log.info("预期和 sum={}", sum);
dynamicContext.setSum(sum);
return router(userId, dynamicContext);
}
@Override
public StrategyHandler getNext(String userId, DynamicContext dynamicContext) {
int mock1 = dynamicContext.getValue("mock1");
int mock2 = dynamicContext.getValue("mock2");
int sum = dynamicContext.getSum();
log.info("mock1={},mock2={},sum={}", mock1, mock2, sum);
if (mock1+mock2== sum) {
log.info("mock1+mock2==sum, 符合预期, 走node2_1节点");
return node2_1;
}
log.info("mock1+mock2!=sum, 不符合预期, 走node2_2节点");
return node2_2;
}
}
```
#### step5: 指定入口节点
```java
@Service
public class DefaultStrategyFactory {
private final Node1 node1;
public DefaultStrategyFactory(Node1 node1) {
this.node1 = node1;
}
public StrategyHandler strategyHandler() {
return node1;
}
}
```
#### step6: 传入参数,执行规则树
```java
StrategyHandler strategyHandler = defaultStrategyFactory.strategyHandler();
String result = strategyHandler.apply("1379666", new DynamicContext());
```
## 3. 设计模式框架 - 责任链
### 3.1. 简介
预先组装好责任链节点,符合条件的请求按顺序执行
### 3.2 优点
- 拆成有针对性的节点,避免一个类中写大量代码
- 便于调整先后顺序
### 3.3 使用方法
#### step1: 引入依赖
```xml
cn.wanyj.component
design-pattern-framework
1.0.0
```
#### step2: 根据需求,自定义上下文实体,并继承`ProceedDynamicContext`类
```java
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class DynamicContext extends ProceedDynamicContext{
private int sum;
private Map dataObjects = new HashMap<>();
public void setValue(String key, T value) {
dataObjects.put(key, value);
}
public T getValue(String key) {
return (T) dataObjects.get(key);
}
}
```
#### step3: 编写各个节点,并实现`ChainHandler`接口
- next(T request, D dynamicContext) 继续执行下一个节点
- stop(T request, D dynamicContext, R result) 停止执行,返回当前结果
```java
@Slf4j
@Component
public class ChainNode1 implements ChainHandler<入参, 上下文实体, 出参> {
@Override
public String apply(String userId, DynamicContext dynamicContext) {
log.info("[ChainNode1]");
return next(userId, dynamicContext);
}
}
```
#### step5: 组装责任链
```java
@Service
public class DefaultChainFactory {
@Bean
public BusinessLinkedList d1(ChainNode1 node1, ChainNode2 node2){
ChainArmory chainArmory = new ChainArmory<>("d1", node1, node2);
return chainArmory.getBusinessLinkedList();
}
}
```
#### step6: 传入参数,执行责任链
```java
@Resource
private BusinessLinkedList businessLinkedList;
String result = businessLinkedList.apply("1379666", new DynamicContext());
```
## 4. 动态限流组件
### 1.1. 简介
使用 Aop 切面技术,基于 Redisson 实现,对用户进行规定时间内的访问频次限制、以及黑名单操作,保证系统安全性
### 1.2 优点
- 保证了分布式场景的数据一致性
- 对用户异常频繁访问行为进行拦截
### 1.3 使用方法
#### step1: 引入依赖
```xml
cn.wanyj.component
rate-limiter-spring-boot-starter
1.0.0
```
#### step2: 针对 Redis 配置 yml
```yml
spring:
data:
redis:
database:
host:
port:
password:
ssl:
timeout:
connectTimeout:
clientName:
cluster:
nodes:
sentinel:
master:
nodes:
```
可以参考Redisson的官方文档:https://redisson.pro/docs/integration-with-spring 按需配置即可
#### step3: 通过注解方式使用
```java
@RateLimiterInterceptor(key = "userId", permitsPerSecond = 1, blacklistCount = 3, blacklistTime = 24, fallbackMethod = "error")
```
- key: 限流标识
- permitsPerSecond: 限制频次(每秒请求次数)
- blacklistCount: 黑名单拦截(多少次限制后加入黑名单)
- blacklistTime: 黑名单时间(多少时间后移出黑名单)默认 24h
- fallbackMethod: 拦截后执行的方法
示例
```java
/**
* 将 userId 作为限流标识,如果每秒请求数量超过 1 次,进行限流,调用 error 方法;
* 如果 1 分钟内总限流次数达到 3 次,则加入黑名单,24h 后移出黑名单
* http://127.0.0.1:8080/api/rl?userId=wanyj
*/
@GetMapping("/rl")
@RateLimiterInterceptor(key = "userId", permitsPerSecond = 1, blacklistCount = 3, blacklistTime = 24, fallbackMethod = "error")
public String rl(String userId) {
log.info("pass: rl");
return "pass: rl";
}
public String error(String userId) {
log.warn("error: rateLimiter");
return "error: rateLimiter";
}
```
#### step4: 全局控制限流功能的开启与关闭
搭配 dcc 动态配置中心使用,直接调整属性值即可
- key: rateLimiterSwitch
- value: open(默认)/close
```java
@Resource
private RTopic dynamicConfigCenterRedisTopic;
dynamicConfigCenterRedisTopic.publish(new AttributeEntity("rateLimiterSwitch", "close"));
```