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

相关推荐
Chen-Edward44 分钟前
有了Spring为什么还有要Spring Boot?
java·spring boot·spring
magic334165631 小时前
Springboot整合MinIO文件服务(windows版本)
windows·spring boot·后端·minio·文件对象存储
开心-开心急了1 小时前
Flask入门教程——李辉 第一、二章关键知识梳理(更新一次)
后端·python·flask
掘金码甲哥1 小时前
调试grpc的哼哈二将,你值得拥有
后端
陈小桔2 小时前
idea中重新加载所有maven项目失败,但maven compile成功
java·maven
小学鸡!2 小时前
Spring Boot实现日志链路追踪
java·spring boot·后端
xiaogg36782 小时前
阿里云k8s1.33部署yaml和dockerfile配置文件
java·linux·kubernetes
逆光的July2 小时前
Hikari连接池
java
微风粼粼2 小时前
eclipse 导入javaweb项目,以及配置教程(傻瓜式教学)
java·ide·eclipse
番茄Salad2 小时前
Spring Boot临时解决循环依赖注入问题
java·spring boot·spring cloud