【事件驱动】两个独立模块如何实现解耦,除了消息队列还有没有其他方式?

前言

先说一下需求。如果用户注册了之后,想发送短信或者邮箱提醒注册成功。又因为用户跟发送信息是两个独立的模块,不想过多耦合。这时候该怎么做?

一般来说可以加一个消息中间件,比如 kafka,这也是最常见的一种方法,高性能。除了这个不加其他技术栈,就用 spring 解决的?

那就是事件驱动ApplicationEvent

正文

ApplicationEvent 是 Spring 框架中用于实现事件驱动编程的关键组件之一。让我详细解释一下:

什么是 ApplicationEvent

  • ApplicationEvent 是 Spring 框架中的一个类,用于表示应用程序中的事件
  • 事件可以是应用程序内部的状态变化、用户操作、外部系统通信等。
  • 通过发布和监听事件,我们可以实现松散耦合的组件之间的通信。

如何使用 ApplicationEvent

  • 创建自定义事件类:可以扩展 ApplicationEvent 类来创建自己的事件。例如,用户注册事件、消息发送事件等。
  • 发布事件:在适当的时机,可以使用 ApplicationEventPublisher 接口发布事件。
  • 监听事件:通过实现事件监听器,可以在事件发生时执行相应的操作。

示例:用户注册事件

  • 首先,我们创建一个自定义事件类 UserRegistrationEvent 继承自 ApplicationEvent

    java 复制代码
    public class UserRegistrationEvent extends ApplicationEvent {
    
        private String username;
    
        public UserRegistrationEvent(Object source, String username) {
            super(source);
            this.username = username;
        }
    
        public String getUsername() {
            return username;
        }
    }
  • 然后,我们创建一个服务类 UserService,用于处理用户注册逻辑并发布事件:

    java 复制代码
    @Service
    public class UserService {
        @Autowired
        private ApplicationEventPublisher eventPublisher;
    
        public void registerUser(String username) {
            // ... 用户注册逻辑 ...
    
            // 发布 UserRegistrationEvent 事件
            eventPublisher.publishEvent(new UserRegistrationEvent(this, username));
        }
    }
  • 再创建消息服务类 Message,用于处理消息发送

    java 复制代码
    @Service
    public class MessageService {
    
        private static Logger logger = LoggerFactory.getLogger(MessageService.class);
    
        public void sendMessage(String username) {
            logger.info("MessageService.sendMessage():{}",username);
        }
    
    }
  • 最后,我们创建一个事件监听器 UserRegistrationListener,以便在用户注册时执行相应的操作:

    java 复制代码
    @Component
    public class UserRegistrationListener {
    
        private Logger logger = LoggerFactory.getLogger(getClass());
    
        private ScheduledExecutorService executorService = null;
    
        @Autowired
        private MessageService messageService;
    
        /**
         * 事件处理监听
         * @param event
         */
        @EventListener
        public void handleUserRegistration(UserRegistrationEvent event) {
            logger.info("监听到一条新的信息:{}", event.getUsername());
    
            // 延迟一段时间后再创建
            if (executorService == null) {
                executorService = Executors.newScheduledThreadPool(1);
            }
            // 延迟一段时间后再执行,防止流程流转时数据还没更新到数据库
            long delayInSeconds = 1; // 延迟1秒
            executorService.schedule(() -> {
                // 执行事件
                messageService.sendMessage(event.getUsername());
            }, delayInSeconds, TimeUnit.SECONDS);
        }
    
        @PreDestroy
        public void destroy() {
            // 执行清理操作
            executorService.shutdown();
        }
    
    }
  • 测试

    java 复制代码
    @RestController
    @RequestMapping("/user/test")
    public class UserController {
    
        private static Logger logger = LoggerFactory.getLogger(UserController.class);
    
        @Autowired
        private UserService userService;
    
        @PostMapping
        public CommonResult userRegistration() {
            String username = "user1";
            logger.info("注册用户:{}" , username);
            userService.registerUser(username);
            return CommonResult.ok();
        }
    
    }

总结

  • 使用 ApplicationEvent,可以构建松散耦合且可扩展的应用程序。
  • 通过自定义事件、事件发布者和事件监听器,您可以实现事件驱动的编程模型,提高应用程序的灵活性和可维护性。
相关推荐
.简.简.单.单.3 分钟前
Design Patterns In Modern C++ 中文版翻译 第八章 组合
java·c++·设计模式
先做个垃圾出来………4 分钟前
创建Flask app应用对象
后端·python·flask
码界奇点7 分钟前
基于Spring Boot和Vue.js的房屋出租管理系统设计与实现
vue.js·spring boot·后端·车载系统·毕业设计·源代码管理
七夜zippoe14 分钟前
Spring MVC请求处理流程源码分析与DispatcherServlet核心逻辑
java·spring·mvc·过滤器·拦截器
笙枫16 分钟前
Agent 进阶设计:状态管理、中间件与多Agent协作
java·服务器·python·ai·中间件
有趣灵魂20 分钟前
Java-根据HTTP链接读取文件转换为base64
java·开发语言·http
YIN_尹24 分钟前
CANN开源仓Catlass模板库核心能力与编程实战
java·开源·dubbo
华如锦24 分钟前
微调—— LlamaFactory工具:使用WebUI微调
java·人工智能·python·ai
幽络源小助理26 分钟前
SpringBoot国内旅游景点数据爬虫与可视化分析系统源码 – JavaWeb项目分享
spring boot·后端·爬虫
武子康29 分钟前
Java-215 RocketMQ 消费模式:Push vs Pull 的本质、长轮询机制与 Offset/积压调优要
java·大数据·分布式·消息队列·rocketmq·java-rocketmq·mq