一、@Async
注解方式
1.配置@Async
在启动类上添加
@EnableAsync
注解开启异步
// 开启异步
@EnableAsync
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
为
@Asnyc
注解配置线程池
@Configuration
public class AsyncConfiguration implements AsyncConfigurer {
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(30);
executor.setQueueCapacity(1024);
executor.setKeepAliveSeconds(180);
executor.setThreadNamePrefix("@Async线程-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
}
2.定义事件
@Setter
@Getter
public class AsyncEvent extends ApplicationEvent {
private String msg;
public AsyncEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
}
3.定义监听器
使用
@EventListener
定义一个监听AsyncEvent
的方法,并使用@Async
注解进行异步处理
@Component
@Slf4j
public class AsyncListener {
/**
* 开启异步监听
* @param asyncEvent 事件
*/
@Async
@EventListener
public void asyncAnnotationListener(AsyncEvent asyncEvent) {
try {
// 模拟耗时
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("asyncAnnotationListener接收到消息:{}", asyncEvent.getMsg());
}
}
4.测试
@SpringBootTest
@Slf4j
public class EventTest {
@Test
public void testAsyncAnnotationEvent() {
log.info("开始发送消息");
AsyncEvent event = new AsyncEvent(this, "@Async异步消息测试");
// hutool工具类,也可以使用ApplicationContext#publishEvent方法
SpringUtil.publishEvent(event);
log.info("发送消息成功");
try {
// 等待listener异步操作完成
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5.结果
事件发布后未被阻塞,过一段时间后监听器完成操作。
二、自定义ApplicationEventMulticaster
方式
1.配置ApplicationEventMulticaster
往Spring容器中注入自定义
SimpleApplicationEventMulticaster
,并设置线程池。注:方法名一定为applicationEventMulticaster
,否则不会生效。
@Configuration
public class EventMulticasterConfiguration {
@Bean
public ApplicationEventMulticaster applicationEventMulticaster(ConfigurableListableBeanFactory configurableListableBeanFactory) {
SimpleApplicationEventMulticaster multicaster = new SimpleApplicationEventMulticaster(configurableListableBeanFactory);
// 自定义线程池
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(2);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(1024);
executor.setKeepAliveSeconds(180);
executor.setThreadNamePrefix("EventMulticaster线程-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
// 给multicaster设置线程池
multicaster.setTaskExecutor(executor);
return multicaster;
}
}
2.定义事件
@Getter
@Setter
public class CustomEvent extends ApplicationEvent {
private String msg;
public CustomEvent(Object source, String msg) {
super(source);
this.msg = msg;
}
}
3.定义监听器
同样用
@EventListener
注解定义一个监听事件的方法,不过不需要添加@Async注解
。
@Component
@Slf4j
public class AsyncListener {
@EventListener
public void customListener(CustomEvent customEvent) {
try {
// 模拟耗时
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("customerListener接收到消息:{}", customEvent.getMsg());
}
}
4.测试
@SpringBootTest
@Slf4j
public class EventTest {
@Test
public void testCustomEventMulticaster() {
log.info("开始发送消息");
CustomEvent event = new CustomEvent(this, "CustomEventMulticaster异步消息测试");
SpringUtil.publishEvent(event);
log.info("发送消息成功");
try {
// 等待listener异步操作完成
TimeUnit.SECONDS.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
5.结果
事件发布后未被阻塞,过一段时间后监听器完成操作。
三、不同
@Async
注解比较灵活,适合项目中既有异步又有同步的场景;而自定义ApplicationEventMulticaster
并配置线程池的方式适合只有异步的场景,一旦配置则全局只能异步。
四、原理
SpringBoot
利用ApplicationEventMulticaster
进行事件的广播,实现类为SimpleApplicationEventMulticaster
。容器启动时,会对ApplicationEventMulticaster
进行初始化,在AbstractApplicationContext#refresh
方法中调用initApplicationEventMulticaster()
方法进行事件多播器初始化:
public static final String APPLICATION_EVENT_MULTICASTER_BEAN_NAME = "applicationEventMulticaster";
protected void initApplicationEventMulticaster() {
// 获取IOC容器
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
// 判断容器中是否存在名为applicationEventMulticaster的Bean
if (beanFactory.containsLocalBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME)) {
// 如果容器中存在则直接用容器中的ApplicationEventMulticaster(在此处拓展)
this.applicationEventMulticaster =
beanFactory.getBean(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, ApplicationEventMulticaster.class);
if (logger.isTraceEnabled()) {
logger.trace("Using ApplicationEventMulticaster [" + this.applicationEventMulticaster + "]");
}
}
else {
// 如果容器中不存在则创建一个SimpleApplicationEventMulticaster,此处创建的Multicaster是没有设置线程池的
this.applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
// 将创建的SimpleApplicationEventMulticaster注入容器中
beanFactory.registerSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, this.applicationEventMulticaster);
if (logger.isTraceEnabled()) {
logger.trace("No '" + APPLICATION_EVENT_MULTICASTER_BEAN_NAME + "' bean, using " +
"[" + this.applicationEventMulticaster.getClass().getSimpleName() + "]");
}
}
}
流程:
- 判断容器中是否存在名为
applicationEventMulticaster
的Bean,如果有则直接使用容器中的bean。这就是上面为什么自定义ApplicationEventMulticaster
的时候方法名只能为applicationEventMulticaster
的原因。 - 如果不存在则创建一个
SimpleApplicationEventMulticaster
,此时创建的Multicaster
是没有设置线程池的(同步)。
发布事件调用的是
AbstractApplicationContext
中的publishEvent
方法 。在publishEvent
方法中又调用applicationEventMulticaster
类中的multicastEvent
方法发布事件。
protected void publishEvent(Object event, @Nullable ResolvableType typeHint) {
//......
if (this.earlyApplicationEvents != null) {
this.earlyApplicationEvents.add(applicationEvent);
}
else if (this.applicationEventMulticaster != null) {
// 在此处对事件进行广播
this.applicationEventMulticaster.multicastEvent(applicationEvent, eventType);
}
//......
}
SimpleApplicationEventMulticaster#multicastEvent
@Override
public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : ResolvableType.forInstance(event));
Executor executor = getTaskExecutor();
// 遍历事件所有监听器
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
// 线程池不为空(默认为空)且listener支持异步(默认都是支持的)
if (executor != null && listener.supportsAsyncExecution()) {
try {
// 在线程池中异步调用
executor.execute(() -> invokeListener(listener, event));
}
catch (RejectedExecutionException ex) {
// Probably on shutdown -> invoke listener locally instead
invokeListener(listener, event);
}
}
else {
// 没有配置线程池或者listener不支持异步,则直接调用
invokeListener(listener, event);
}
}
}
protected void invokeListener(ApplicationListener<?> listener, ApplicationEvent event) {
ErrorHandler errorHandler = getErrorHandler();
if (errorHandler != null) {
try {
doInvokeListener(listener, event);
}
catch (Throwable err) {
errorHandler.handleError(err);
}
}
else {
doInvokeListener(listener, event);
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) {
try {
// 直接调用监听器中的方法
listener.onApplicationEvent(event);
}
catch (ClassCastException ex) {
String msg = ex.getMessage();
if (msg == null || matchesClassCastMessage(msg, event.getClass()) ||
(event instanceof PayloadApplicationEvent payloadEvent &&
matchesClassCastMessage(msg, payloadEvent.getPayload().getClass()))) {
// Possibly a lambda-defined listener which we could not resolve the generic event type for
// -> let's suppress the exception.
Log loggerToUse = this.lazyLogger;
if (loggerToUse == null) {
loggerToUse = LogFactory.getLog(getClass());
this.lazyLogger = loggerToUse;
}
if (loggerToUse.isTraceEnabled()) {
loggerToUse.trace("Non-matching event type for listener: " + listener, ex);
}
}
else {
throw ex;
}
}
}
SimpleApplicationEventMulticaster#multicastEvent
先判断是否配置了线程池,如果配置了线程池,则在线程池用异步调用,如果没有配置线程池则直接调用。