spring|spring event高性能|Spring内置事件驱动编程模型
从同步阻塞到异步非阻塞
默认是同步且阻塞,发布线程会串行依次执行所有监听器。任何一个监听器的耗时操作都会阻塞主流程,可能导致严重的性能问题
源码
https://gitee.com/jysemel-spring/spring-boot/tree/master/action/action-event-async
开启异步
- 启用异步支持
配置类上添加@EnableAsync注解
- 标记异步监听器
@Component
public class AsyncNotificationListener {
@Async
@EventListener
public void handleUserRegisteredEvent(UserRegisteredEvent event) {
// 此逻辑将在独立线程中执行
System.out.println("异步发送欢迎邮件给用户:" + event.getUserId());
}
}
异步样例
启动类
package com.jysemel.spring.boot;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@SpringBootApplication
public class Main {
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
}
两种不同的监听方式(通过注释来分别调试异步和同步)
package com.jysemel.spring.boot.study.listener;
import com.jysemel.spring.boot.study.event.UserRegisteredEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 方式二:使用@EventListener注解(更推荐)
*/
@Slf4j
@Component
public class CouponListener {
@Async
@EventListener
public void handleUserRegisteredEvent(UserRegisteredEvent event) throws InterruptedException {
log.info("方式二:使用@EventListener注解 @Async异步监听处理 ");
try {
Thread.sleep(TimeUnit.MINUTES.toMillis(5));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("赠送新人优惠券给用户:{} ", event.getNickName());
}
}
package com.jysemel.spring.boot.study.listener;
import com.jysemel.spring.boot.study.event.UserRegisteredEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 方式一:实现ApplicationListener接口
*/
@Slf4j
@Component
public class WelcomeEmailListener implements ApplicationListener<UserRegisteredEvent> {
@Override
public void onApplicationEvent(UserRegisteredEvent event) {
log.info("方式一:普通监听 ");
try {
Thread.sleep(TimeUnit.MINUTES.toMillis(5));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("发送欢迎邮件给用户: {}" ,event.getNickName());
}
}
验证地址
http://127.0.0.1:8083/api/user/reg?userName=113.9526&nickName=22.5431
验证结果
- 异步方式,线程id不一样
2026-07-14 11:49:13.600 [http-nio-8083-exec-1] [] INFO com.jysemel.spring.boot.study.controller.UserRegController - 用户注册:113.9526
2026-07-14 11:49:13.600 [http-nio-8083-exec-1] [] INFO com.jysemel.spring.boot.study.service.StoreService - 用户 22.5431 注册成功
2026-07-14 11:49:13.602 [task-2] [] INFO com.jysemel.spring.boot.study.listener.CouponListener - 方式二:使用@EventListener注解 @Async异步监听处理
2026-07-14 11:49:14.402 [http-nio-8083-exec-2] [] INFO com.jysemel.spring.boot.study.controller.UserRegController - 用户注册:113.9526
2026-07-14 11:49:14.402 [http-nio-8083-exec-2] [] INFO com.jysemel.spring.boot.study.service.StoreService - 用户 22.5431 注册成功
2026-07-14 11:49:14.403 [task-3] [] INFO com.jysemel.spring.boot.study.listener.CouponListener - 方式二:使用@EventListener注解 @Async异步监听处理
- 同步方式,线程id一样,上面接口明显阻塞
2026-07-14 11:52:39.886 [http-nio-8083-exec-1] [] INFO org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
2026-07-14 11:52:39.886 [http-nio-8083-exec-1] [] INFO org.springframework.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
2026-07-14 11:52:39.889 [http-nio-8083-exec-1] [] INFO org.springframework.web.servlet.DispatcherServlet - Completed initialization in 3 ms
2026-07-14 11:52:39.928 [http-nio-8083-exec-1] [] INFO com.jysemel.spring.boot.study.controller.UserRegController - 用户注册:113.9526
2026-07-14 11:52:39.930 [http-nio-8083-exec-1] [] INFO com.jysemel.spring.boot.study.service.StoreService - 用户 22.5431 注册成功
2026-07-14 11:52:39.931 [http-nio-8083-exec-1] [] INFO com.jysemel.spring.boot.study.listener.WelcomeEmailListener - 方式一:普通监听
当前方式存在的问题
- 队列无限大
- 无线程复用

自定义异步线程池
package com.jysemel.spring.boot.study.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
public class AsyncConfig {
@Bean(name = "eventExecutor")
public Executor eventExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5); // 核心线程数
executor.setMaxPoolSize(20); // 最大线程数(必须小于操作系统限制)
executor.setQueueCapacity(200); // 有界队列,防止OOM
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("event-async-");
// 关键:当队列和最大线程都满了,由调用者线程执行(防止任务丢失,并提供背压机制)
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}

优化调整,显示指定线程池
package com.jysemel.spring.boot.study.listener;
import com.jysemel.spring.boot.study.event.UserRegisteredEvent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import java.util.concurrent.TimeUnit;
/**
* 方式二:使用@EventListener注解(更推荐)
*/
@Slf4j
@Component
public class CouponListener {
@Async("eventExecutor")
@EventListener
public void handleUserRegisteredEvent(UserRegisteredEvent event) throws InterruptedException {
log.info("方式二:使用@EventListener注解 @Async异步监听处理 ");
try {
Thread.sleep(TimeUnit.SECONDS.toMillis(10));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
log.info("赠送新人优惠券给用户:{} ", event.getNickName());
}
}
