掘金 后端 ( ) • 2024-04-11 18:04

前言

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

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

那就是事件驱动ApplicationEvent

正文

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

什么是 ApplicationEvent

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

如何使用 ApplicationEvent

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

示例:用户注册事件

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

    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,用于处理用户注册逻辑并发布事件:

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

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

    
    @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();
        }
    
    }
    
    
  • 测试

    
    @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();
        }
    
    }
    
    

image-20240411174342693.png

总结

  • 使用 ApplicationEvent,可以构建松散耦合且可扩展的应用程序。
  • 通过自定义事件、事件发布者和事件监听器,您可以实现事件驱动的编程模型,提高应用程序的灵活性和可维护性。