springboot中的策略模式
场景介绍:
底层agent扫描云主机中安装的各类中间件,以OS为维度全量上报。
服务层需要拆分入库,并且判断是否已注册。例如:kafka、redis、was、tomcat、pgsql、Hadoop、linux、windows等等吧。
我们可以用一堆if..else 进行各种判断,也可以用传统的策略模式,new一个一个对象,分别处理。
但是这都不是优雅的编程方式,更不满足开闭原则。
做一个3秒程序员,上面那些方式不是我们要做的。
例如,业务下次扫描范围增加了,k8s,clickhouse、elasticsearch等,就要修改原始代码。
Springboot采用的是注册机制,启动会生成一个一个bean,使用时只需要注入即可。
所有传统的策略模式需要升级为Springboot+策略模式,核心就是自定义注解和@Autowired.
- context
- 行为接口
- 自定义注解 - -用于生成和寻找对应bean
- 具体bean
1、自定义注解
用来标志各种资源bean,一一对应。
/**
* desc
*
* @Author 红尘过客
* @DateTime 2023-08-02 16:05:23
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Service
public @interface SourceType {
/**
* 资源类型
*
* @return
*/
String type();
}
2、行为接口
接口由来标志对应能力
可以对json对象,vo对象等进行处理。
/**
* 资源上报处理策略
*
* @Author 红尘过客
* @DateTime 2023-08-02 16:09:21
*/
public interface ISourceHandleStrategy {
void handle(JSONObject sourceJson);
}
3、策略上下文
package com.wht.test.strategy;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 上报资源处理策略上下文
* 本质是容器中收录所有处理器
*
* @Author 红尘过客
* @DateTime 2023-08-02 16:12:56
*/
@Service
public class SourceHandleContext {
private Map<String, ISourceHandleStrategy> sourceHandleStrategyMap;
/**
* 上下文装载所有处理器
*
* @param list
*/
@Autowired
public void setSourceHandleStrategyMap(List<ISourceHandleStrategy> list) {
sourceHandleStrategyMap = list.stream().collect(Collectors.toMap(
sourceHandleStrategy -> AnnotationUtils.findAnnotation(sourceHandleStrategy.getClass(),
SourceType.class).type(), sourceHandleStrategy -> sourceHandleStrategy,
(value1, value2) -> value1));
}
public void handle(JSONObject jsonObject) {
String type = jsonObject.getString("source_type"); // 加入go-agent扫描上来的对象,用source_type标注类型
if (sourceHandleStrategyMap != null && sourceHandleStrategyMap.size() > 0) {
ISourceHandleStrategy sourceHandleStrategy = sourceHandleStrategyMap.get(type);
if (sourceHandleStrategy != null) {
// 如果对应中间件有对应的处理器,就进行上报等处理
sourceHandleStrategy.handle(jsonObject);
}
}
}
}
4、增加两个处理器
was处理器
/**
* desc
*
* @Author 红尘过客
* @DateTime 2023-08-02 16:24:22
*/
@SourceType(type = "was")
@Slf4j
public class WasHandler implements ISourceHandleStrategy{
@Override
public void handle(JSONObject sourceJson) {
log.info("was 处理器处理逻辑");
}
}
oracle处理器
@SourceType(type = "oracle")
@Slf4j
public class OracleHandler implements ISourceHandleStrategy{
@Override
public void handle(JSONObject sourceJson) {
log.info("oracle 处理器处理逻辑");
}
}
5、使用示例
只需拿到上下文,把要处理的数据扔进去,就可以按照对应的策略,自动找到对应的bean进行处理。
@Slf4j
@Component
public class TestClient {
@Autowired
private SourceHandleContext sourceHandleContext;
@Scheduled(cron = "* * * * * * ")
public void bizHandler(){
JSONObject jsonObject = new JSONObject();
jsonObject.put("source_type","was");
sourceHandleContext.handle(jsonObject);
}
}
看下运行结果:
2023-08-02 16:35:54.006 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:35:55.003 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:35:56.012 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:35:57.003 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:35:58.008 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:35:59.011 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:36:00.007 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:36:01.007 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:36:02.016 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑
2023-08-02 16:36:03.013 INFO 12172 --- [ scheduling-1] com.wht.test.strategy.WasHandler : was 处理器处理逻辑