我提出了两个场景,一个是使用bean工厂注册的bean,另一个是通过自动扫描包注释定义创建的bean(例如@Component
)。 bean类使用注释为ContextRefreshedEvent
的方法以及@EventListener
来监听@Async
,以便异步调用它。
创建一个类BlockingListener
的单例并在bean工厂注册。这是在另一个Bean的初始化时完成的,如下面方法afterPropertiesSet
中所述。 已收到ContextRefreshedEvent
但未退出,因此应用程序无法启动。它仍然受阻。
@EnableAsync
@EnableScheduling
@EnableAutoConfiguration
@SpringBootApplication
public class SampleApp implements InitializingBean {
private final DefaultListableBeanFactory beanFactory;
@Autowired
public SampleApp(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
@Override
public void afterPropertiesSet() {
String beanName = "blocking-listener";
Object bean = new BlockingListener();
beanFactory.registerBeanDefinition(beanName, rootBeanDefinition(bean.getClass()).getBeanDefinition());
beanFactory.registerSingleton(beanName, bean);
}
public static void main(final String... args) {
SpringApplication.run(SampleApp.class, args);
}
public static class BlockingListener {
@Async
@EventListener(ContextRefreshedEvent.class)
void block() throws InterruptedException {
Thread.sleep(Long.MAX_VALUE);
}
}
}
类BlockingListener
注释为@Component
,并自动检测并创建bean。 已收到ContextRefreshedEvent
但未退出,但应用程序已启动。
@EnableAsync
@EnableScheduling
@EnableAutoConfiguration
@SpringBootApplication
public class SampleApp {
private final DefaultListableBeanFactory beanFactory;
@Autowired
public SampleApp(DefaultListableBeanFactory beanFactory) {
this.beanFactory = beanFactory;
}
public static void main(final String... args) {
SpringApplication.run(SampleApp.class, args);
}
@Component
public static class BlockingListener {
@Async
@EventListener(ContextRefreshedEvent.class)
void block() throws InterruptedException {
Thread.sleep(Long.MAX_VALUE);
}
}
}
预期的行为是第二个场景,因为ContextRefreshedEvent应该在上下文成功启动后发布。但是,我无法弄清楚为什么动态注册bean的bean在上下文启动之前收到了事件,以及为什么它阻止了上下文的启动。
答案 0 :(得分:2)
在方案1中,block()
的调用不会异步发生,因为注释@Async
无法生效。
@Async
正在使用BeanPostProcessor
,即使用代理包装实例的AsyncAnnotationBeanPostProcessor
。但是当您手动将bean添加到bean工厂时,不会应用后处理器。
您在给定设置中可以执行的操作是将后处理器手动应用为:
bean = beanFactory.initializeBean(bean, beanName);
beanFactory.registerSingleton(beanName, bean);