首页 > 其他分享 >策略模式+Spring配置类优化多if..else思路

策略模式+Spring配置类优化多if..else思路

时间:2023-07-28 10:22:07浏览次数:37  
标签:return String .. Spring else bizUpMessage handler identification public

图示

image

1. 现状

场景: 假设设备上报不同类型的消息,我们要对不同类型的消息做不同的处理。如果我们通过if..else的方式处理的话会显得比较冗余。

例如:

if("alarmEvent".equals(msg)){
    // 处理告警消息逻辑 ...
}else if("deviceBase".equals(msg)){
    // 处理设备上报的基本信息 ...
}else if("heartBeat".equals(msg)){
    // 处理设备心跳消息 ...
}else {
    // ...
}

2. 消息处理Handler

那么对于不同消息的不同的处理逻辑我们可以单独放在一个实现类中,这些类有着相同的行为,所以我们可以定义一个接口:

public interface MessageHandler<T>{
    T invoke(String bizUpMessage); // 处理接收到的消息
    String getName();
    String getIdentification(); // 获取消息标志
}

针对于不同的消息,我们可以有各自的实现

实现类1:

@Component
public class DeviceBaseInfoHandler implements MessageHandler<String> {

    @Override
    public String invoke(String bizUpMessage) {
        // 处理设备上报的基本信息 ...
        return "";
    }

    @Override
    public String getName() {
        return "";
    }

    @Override
    public String getIdentification() {
        return "DeviceBaseInfoRequest";
    }
}

实现类2:

@Component
public class AlarmEventHandler implements MessageHandler<String>{

    @Override
    public String invoke(String bizUpMessage) {
       // 处理告警信息 ...
        return null;
    }

    @Override
    public String getName() {
        return "";
    }

    @Override
    public String getIdentification() {
        return "AlarmEventRequest";
    }
}

3. Handler注册处

我们可以将上一步的消息处理对象,根据消息的标志(Identification)不同,将消息放在一个Map中:

public class MessageHandlerRegisty {

    private Map<String, List<MessageHandler>> registerMap = new HashMap<>();

    // 注册各种 handler
    public void regist(String identification, MessageHandler handler){
        if(this.contains(identification)){
            get(identification).add(handler);
        } else {
            List<MessageHandler> list = new ArrayList<>();
            list.add(handler);
            registerMap.put(identification, list);
        }
    }

    public boolean contains(String identification){
        return registerMap.containsKey(identification);
    }

    public List<MessageHandler> get(String identification){
        return registerMap.get(identification);
    }
}

4. 消息接收Service

消息接收接口

public interface IMessageService {
    void messageReceived(String bizUpMessage); // 接收消息
}

5. 消息接收ServiceImpl

消息接收实现类

public class MessageServiceImpl implements IMessageService{
    
    public MessageHandlerRegisty registy;
    
    // 线程池
    public ExecutorService executorService = new ThreadPoolExecutor(3, 10, 15, TimeUnit.MINUTES, new LinkedBlockingQueue(1000), new LogdDiscardPolicy());
    
    public void messageReceived(String bizUpMessage){
        
        // 获取消息的标志Identification
        String identification = extractIdentification(bizUpMessage);
        
        if(StringUtils.isBlank(identification)){ 
            return;
        }
        
        if(!registy.contains(identification)){  
            return;
        }
        
        for(MessageHandler handler : registy.get(identification)){
            execute(handler, bizUpMessage); // 多线程处理消息
        }
    }
    
    public MessageHandlerRegisty getRegisty() {
        return registy;
    }
    public void setRegisty(MessageHandlerRegisty registy) {
        this.registy = registy;
    }
    
    private void execute(MessageHandler handler, String bizUpMessage){
        executorService.submit(new IotMessageTask(handler, bizUpMessage));
    }
    
    public final class LogdDiscardPolicy extends ThreadPoolExecutor.DiscardPolicy {
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            log.warn("MessageService pool is full !!!!!!!!");
        }
    }
    
    
    final class IotMessageTask implements Runnable {

        private MessageHandler handler;
        private String bizUpMessage;

        public IotMessageTask(MessageHandler handler, String bizUpMessage){
            this.handler = handler;
            this.bizUpMessage = bizUpMessage;
        }

        @Override
        public void run() {
            try {
                Stopwatch stopwatch = Stopwatch.createStarted();
                handler.invoke(bizUpMessage);
                stopwatch = stopwatch.stop();
                
                long cost = stopwatch.elapsed(TimeUnit.MICROSECONDS);
                logTime(cost);
            }catch (Exception e){
                log.error("handler execute error - ", e);
            }
        }

        private void logTime(long cost){
            if(cost > 50){
                log.warn(" handler -> {}, cost too much -> {}", handler.getName(), cost);
            } else {
                log.info("handler -> {}, cost -> {}", handler.getName(), cost);
            }
        }
        
    }

    
    
}

6. 将MessageServiceImpl对象配置到spring容器

@Configuration
public class ManagerConfig {

    @Bean
    public IMessageService messageService(){
        MessageServiceImpl messageService = new MessageServiceImpl();
        messageService.setRegisty(buildRegisty());
        return messageService;
    }

    // 消息处理handler
    @Autowired
    private DeviceBaseInfoHandler deviceBaseInfoHandler;
    @Autowired
    private AlarmEventHandler alarmEventHandler;
    
    private MessageHandlerRegisty buildRegisty(){
        MessageHandlerRegisty registy = new MessageHandlerRegisty();
        registy.regist(deviceBaseInfoHandler.getIdentification(), deviceBaseInfoHandler);
        registy.regist(alarmEventHandler.getIdentification(),alarmEventHandler);
        
        return registy;
    }
}

标签:return,String,..,Spring,else,bizUpMessage,handler,identification,public
From: https://www.cnblogs.com/charlton/p/17586887.html

相关文章

  • SpringCloud的注册和发现
    什么是微服务架构,为什么要用将原本属于一个项目的根据业务划分模块,部署到不同的服务器上,通过接口相互调用。好处:如果部署在一台服务器上,服务器崩溃后所有功能都不能使用。如果使用的时微服务架构,一个服务器崩了,不会对另一个模块造成很大影响每个微服务项目复杂性低技术更新迭......
  • springMVC Interceptor 拦截器
    1.springMVCInterceptor拦截器2.Filter和Interceptor比对3.HandlerInterceptor接口方法的作用及其参数、返回值详解4.springMVC拦截器执行顺序 ......
  • springboot上传图片后通过http访问图片
    需要上传图片或pdf文件,放在服务器本地磁盘中,比如window服务器的D:/YG/盘符下,此时想要通过http的方式直接访问图片或pdf 1.图片存储在本地磁盘,实现WebMvcConfigurer接口添加本地静态资源访问过滤2.图片存储在本地磁盘,nginx动静分离  第一种方式:@Configurationpubli......
  • Shiro实战教程(整合SpringBoot,全网最强)
    ​ 本文介绍一个强大的Shiro实战教程,用最简单的代码、最常用的场景让你彻底掌握Shiro的用法,成为Shiro实战高手。本Shiro教程是全网最强的Shiro实战教程。教程地址:Shiro项目实战专栏介绍-自学精灵为什么这个Shiro教程是全网最强?其他资料的特点代码不全,根本运行不起来。不......
  • Sa-Token简单几行代码,优雅的实现 SpringBoot 鉴权
    一、添加依赖二、设置配置文件三、创建测试Controller:登录接口四、创建测试Controller:普通访问接口五、检验当前会话是否已经登录六、路由拦截鉴权七、自定义全局异常拦截添加依赖<dependency><groupId>cn.dev33</groupId><artifactId>......
  • springboot实现链接生成QrCode
    1.注入依赖<dependency><groupId>com.google.zxing</groupId><artifactId>core</artifactId><version>3.3.0</version></dependency><dependency><groupId>com.google.zxing</groupId>......
  • 使用Docker安装Apollo并使用SpringBoot连接配置中心
    上篇文章我们学习了Apollo的本地安装,如果还不会本地安装的朋友可以查看之前的文章进行了解和学习链接地址(https://www.cnblogs.com/eternality/p/17583023.html),本篇我们学习怎么使用Docker安装Apollo及如何使用Java连接Apollo。阅读本篇文章需要了解docker安装容器相关的使用命令,......
  • SpringBoot 开启GZIP数据压缩
    I.gizp压缩配置1.配置SpringBoot默认是不开启gzip压缩的,需要我们手动开启,在配置文件中添加两行server:compression:enabled:truemime-types:application/json,application/xml,text/html,text/plain,text/css,application/x-javascript注意下上面配置中......
  • for...in 循环和 for...of 循环的区别
    JavaScript中的for...in循环和for...of循环是两种不同的迭代方式,用于遍历数据结构中的元素。它们具有一些区别:for...in循环:用于遍历对象的可枚举属性(包括原型链上的属性)。迭代的是键(属性名),而非值。不保证迭代顺序,因为对象的属性顺序在规范中并未定义。比较适合用于遍......
  • 【Spring Cloud】服务注册、发现与调用的核心原理
    参考:https://www.bilibili.com/video/BV1i14y1D7DY/?spm_id_from=333.337.search-card.all.click 给出核心的几个类,与之间交互说明、 服务注册: NacosAutoServiceRegistration实现了spring的事件监听,当web初始化完成后进行服务的注册  服务发现  服务调用......