聊聊Spring事件机制

一、前言

在我们平时的开发工作当中,肯定有这样一些业务场景,这块业务完成后,就给用户推送一些消息以提醒用户,比如给用户发送一条下单成功信息,对于这种非核心的业务功能其实我们可以单独拿出来,创建一个事件去异步执行,这样子就可以实现核心业务和子业务的解耦。

二、具体实现步骤

  1. 首先定义一个事件类Event

    java 复制代码
    public class NoticeEvent extends ApplicationEvent {
        private String message;
    
        public NoticeEvent(String message) {
            super(message);
            this.message = message;
        }
    
        public String getMessage() {
            return message;
        }
    }

    所有事件类都需要继承ApplicationEvent

创建事件监听类
java 复制代码
@Component
public class NoticeListener implements ApplicationListener<NoticeEvent> {

    private static final Logger logger = LoggerFactory.getLogger(NoticeListener.class);

    @Override
    public void onApplicationEvent(NoticeEvent event) {
        try {
            logger.info("接收到的消息:{}",event);
            //模拟处理消息
            Thread.sleep(5000);
            logger.info("处理消息完成:{}",event);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}

该类用于监听指定事件的类,需要实现ApplicationListener接口。注意这里需要加上@Component注解,将其注入Spring容器中。
3. 发布事件

java 复制代码
@RestController
@RequestMapping("/event")
public class EventController {
    private static final Logger logger = LoggerFactory.getLogger(EventController.class);
    @Autowired
    private ApplicationEventPublisher publisher;

    @GetMapping("/notice/{message}")
    public void notice(@PathVariable(name = "message")String message) {
        logger.info("开始发送消息:{}",message);
        publisher.publishEvent(new NoticeEvent(message));
        logger.info("消息发送完成");
    }
}

使用Spring 提供的ApplicationEventPublisher来发布自定义事件。

代码写完了,我们直接来测试看效果:

启动服务,访问接口:http://localhost:8003/batch/event/notice/testMessage

我们可以看到,从始至终都是同一条线程去完成这个任务的,并没有异步去执行。

从这里我们可以得知,默认是没有开启异步的,我们需要手动配置开启异步功能,我们需要在启动类中加上@EnableAsync注解,该注解用于声明启用Spring的异步方法执行功能。然后我们在监听方法上加上@Async注解,说明当前方法使用异步去执行。

然后测试:

从截图可以看出,已经实现了异步功能,主线程为http-nio-8003-exec-1,监听线程为 task-1。从日志打印可以看出,接口直接返回了,并没有等监听线程执行完后才返回。

这里我们再提一点,开启异步后,会使用Spring内部默认的线程池,我们可以自定义这个线程池,如下:

java 复制代码
@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * 自定义异步线程池,若不重写会使用默认的线程池
     */
    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
        // 核心线程数
        taskExecutor.setCorePoolSize(2);
        // 最大线程数
        taskExecutor.setMaxPoolSize(10);
        // 队列大小
        taskExecutor.setQueueCapacity(15);
        // 线程名的前缀
        taskExecutor.setThreadNamePrefix("async-thread-");
        taskExecutor.initialize();
        return taskExecutor;
    }
}

测试:

已经使用上我们自定义的线程池了。

好了,关于Spring中的ApplicationEvent和ApplicationListener我们就介绍这么多。

相关推荐
㳺三才人子3 小时前
初探 Flask
后端·python·flask·html
星栈独行3 小时前
我在 Rust 全栈项目里用 JWT 做无状态认证
开发语言·后端·rust·前端框架·开源·github·web
Lei活在当下3 小时前
先用起来,再理解,关于协程Coroutine应该知道的事
android·java·jvm
Java爱好狂.4 小时前
Java程序员体系化学习路线(2026最新版)
java·后端·java面试·java架构师·java程序员·java八股文·java学习路线
陈随易4 小时前
Redis 8.8发布,一定要更新
前端·后端·程序员
tongluowan0074 小时前
以ReentrantLock为例解释AQS的工作流程
java·模板方法模式·aqs·reentrantlock
装不满的克莱因瓶4 小时前
SpringBoot 如何将 lib 目录中jar包打包进最终的jar包里面
spring boot·后端·maven·jar·mvn
ltl5 小时前
Transformer 原论文实验结果:为什么 28.4 BLEU 足以改写路线图
后端
身如柳絮随风扬5 小时前
Java 项目打包与部署完全指南:JAR vs WAR,从构建到运行
java·firefox·jar
云烟成雨TD6 小时前
Spring AI Alibaba 1.x 系列【62】时光旅行(Time-Travel)
java·人工智能·spring