一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第25天,点击查看活动详情。
1、错误的使用
最近发现有小伙伴在代码里错误的使用@Async注解,这样用是不会生效的;
2、为什么不能这样写?
2.1、先看@Async注解使用条件:
@Async注解一般用在类的方法上,如果用在类上,那么这个类所有的方法都是异步执行的; 所使用的@Async注解方法的类对象应该是Spring容器管理的bean对象; 调用异步方法类上需要配置上注解@EnableAsync 默认情况下(即@EnableAsync注解的mode=AdviceMode.PROXY)
2.2、还要了解@EnableAsync 原理
2.2.1、EnableAsync
SpringBoot当要使用@Async时,需启动类显示声明@EnableAsync 来 注入 AsyncConfigurationSelector(一个AdviceModeImportSelector);默认AdviceMode.PROXY
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
//用户定义的需要进行异步执行的注解,默认只有Async注解
Class<? extends Annotation> annotation() default Annotation.class;
//是否创建基于CGLIB的代理对象
boolean proxyTargetClass() default false;
//代理模式选择 PROXY表示jdk的代理
AdviceMode mode() default AdviceMode.PROXY;
//对应的AsyncAnnotationBeanPostProcessor的拦截顺序
int order() default Ordered.LOWEST_PRECEDENCE;
}
2.2.2、ProxyAsyncConfiguration
最终注入的是ProxyAsyncConfiguration
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
//默认的是jdk PROXY的模式
case PROXY:
return new String[] {ProxyAsyncConfiguration.class.getName()};
//使用AspectJ的模式
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
2.2.3、AsyncAnnotationBeanPostProcessor
构建了一个内部含Advisor的类:AsyncAnnotationBeanPostProcessor。
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public class ProxyAsyncConfiguration extends AbstractAsyncConfiguration {
@Bean(name = TaskManagementConfigUtils.ASYNC_ANNOTATION_PROCESSOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public AsyncAnnotationBeanPostProcessor asyncAdvisor() {
Assert.notNull(this.enableAsync, "@EnableAsync annotation metadata was not injected");
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
//设置executor跟exceptionHandler,spring都是空实现,也就是这两个值都是null,后面会设置默认的对象,也可以自己指定实现,
bpp.configure(this.executor, this.exceptionHandler);
Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
//如果annotation值不是默认的,则将这个加入到AsyncAnnotationBeanPostProcessor,后面进行拦截用
if (customAsyncAnnotation != AnnotationUtils.getDefaultValue(EnableAsync.class, "annotation")) {
bpp.setAsyncAnnotationType(customAsyncAnnotation);
}
bpp.setProxyTargetClass(this.enableAsync.getBoolean("proxyTargetClass"));
bpp.setOrder(this.enableAsync.<Integer>getNumber("order"));
return bpp;
}
}
AsyncAnnotationBeanPostProcessor 继承了 BeanFactoryAware 接口。在setBeanFactory方法中,初始化了AsyncAnnotationAdvisor