@Async注解的方法所属的spring bean,不能注入到自身的属性中。
使用及问题
使用@Async
注解需要在配置类中声明@EnableAsync
,以启动此注解的支持。
当我们开启了@Async
,并循环依赖当前bean
时,启动会报错BeanCurrentlyInCreationException
。
解决方法,将这段异步逻辑单独抽取到另一个bean
中。
案例代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
@Slf4j
@Service
// TODO 即使加了懒加载,启动时不报错,但只要调用getBean()时,还是会报错。
//@Lazy
public class AsyncServiceImpl implements AsyncService {
@Resource
private AsyncService asyncService;
@Async
@Override
public void asyncExecute() {
asyncService.execute();
}
@Override
public void execute() {
log.info("异步执行业务代码...");
}
}
|
原因
- 看注解
@EnableAsync
的声明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
// TODO 这里导入了一个ImportSelector
@Import(AsyncConfigurationSelector.class)
public @interface EnableAsync {
Class<? extends Annotation> annotation() default Annotation.class;
boolean proxyTargetClass() default false;
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
|
@Import(AsyncConfigurationSelector.class)
中,导入了一个ImportSelector
。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
@Override
@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
// TODO spring启动时,会加载这个类。这是一个 @Configuration 注解的类。
return new String[] {ProxyAsyncConfiguration.class.getName()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
|
- 看配置类中加载了什么
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
@Configuration
@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");
// TODO 异步注解bean处理器。所有@Async注解的方法,对应bean都会被它处理。
AsyncAnnotationBeanPostProcessor bpp = new AsyncAnnotationBeanPostProcessor();
bpp.configure(this.executor, this.exceptionHandler);
Class<? extends Annotation> customAsyncAnnotation = this.enableAsync.getClass("annotation");
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
extends AbstractBeanFactoryAwareAdvisingPostProcessor
extends AbstractAdvisingBeanPostProcessor
implements BeanPostProcessor
查看源码,异步代理对象是在bean初始化之后生成的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
public abstract class AbstractAdvisingBeanPostProcessor extends ProxyProcessorSupport implements BeanPostProcessor {
/**
* TODO 此方法是bean实例创建、依赖注入、初始化方法执行后,才执行的。
*/
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (this.advisor == null || bean instanceof AopInfrastructureBean) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
if (bean instanceof Advised) {
Advised advised = (Advised) bean;
if (!advised.isFrozen() && isEligible(AopUtils.getTargetClass(bean))) {
// Add our local Advisor to the existing proxy's Advisor chain...
if (this.beforeExistingAdvisors) {
advised.addAdvisor(0, this.advisor);
} else {
advised.addAdvisor(this.advisor);
}
return bean;
}
}
if (isEligible(bean, beanName)) {
ProxyFactory proxyFactory = prepareProxyFactory(bean, beanName);
if (!proxyFactory.isProxyTargetClass()) {
evaluateProxyInterfaces(bean.getClass(), proxyFactory);
}
proxyFactory.addAdvisor(this.advisor);
customizeProxyFactory(proxyFactory);
return proxyFactory.getProxy(getProxyClassLoader());
}
// No proxy needed.
return bean;
}
}
|
spring中bean实例创建后会提前暴露引用,所以在依赖注入之前可以获取到bean实例。也是基于此实现了循环依赖注入。
而@Async
注解,是在依赖注入之后,才生成的代理对象,这是自相矛盾的。所以在使用@Async
注解的方法所在类的bean
不允许循环依赖注入。