聊聊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我们就介绍这么多。

相关推荐
小小张说故事4 小时前
BeautifulSoup:Python网页解析的优雅利器
后端·爬虫·python
怒放吧德德4 小时前
后端 Mock 实战:Spring Boot 3 实现入站 & 出站接口模拟
java·后端·设计
biyezuopinvip4 小时前
基于Spring Boot的企业网盘的设计与实现(任务书)
java·spring boot·后端·vue·ssm·任务书·企业网盘的设计与实现
UrbanJazzerati4 小时前
Python编程基础:类(class)和构造函数
后端·面试
脸大是真的好~4 小时前
EasyExcel的使用
java·excel
小宋10214 小时前
Java 项目结构 vs Python 项目结构:如何快速搭一个可跑项目
java·开发语言·python
楚兴4 小时前
MacBook M1 安装 OpenClaw 完整指南
人工智能·后端
JavaGuide5 小时前
一款悄然崛起的国产规则引擎,让业务编排效率提升 10 倍!
java·spring boot
吃虫子的人5 小时前
记录使用Arthas修改线上源码重新加载的一次过程
java·arthas