现象
最近项目中使用了spring中的异步处理@EnableAsync
和定时任务@EnableSchedule
,二者作用在同一个service中,导致异步方法失效,最终发现还是不了解后置处理器作用导致的,还是图样图森破。
BeanPostProcessor
该接口的两个方法如下,都与Bean的生命周期有密切联系,
不了解bean生命周期的同学参考
postProcessBeforeInitialization()
这个方法作用于bean的初始化之前,init-method
指定的方法- 重写
InitializingBean
接口的afterPropertiesSet()
方法 @PostConstruct
注解标注的方法
postProcessAfterInitialization()
该方法作用于初始化完成之后
源码解读
我们知道,spring的入口在AbstractApplicationContext
的refresh()
方法中,如图:
其中框起来的方法,就是扫描容器中的BeanPostProcessor
过程,在执行到该方法时候,容器中已经默认添加了几个BeanPostProcessor
实例对象,注意,是实例。如下图示:
接下来就是执行registerBeanPostProcessors()
方法
public static void registerBeanPostProcessors(
ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// 从容器中获取所有`BeanPostProcessor`的bean定义
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
// 注册一个后置处理器检查器,本身也是一个BeanPostProcessor,
// 当容器的日志级别是info时,打印出没有被所有BeanPostProcessor作用的bean对象
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
//将这个后置处理器检查器注入到BeanFactory中,所有的bean初始化会遍历bean工厂中的后置处理器集合,作用到每个bean的初始化中
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// 将实现了不同接口的后置处理器分别单独处理 ,实现了同一接口的后置处理器属于一类,同一类不能相互作用,优先级的顺序是,PriorityOrdered,Ordered, others
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<BeanPostProcessor>();
List<String> orderedPostProcessorNames = new ArrayList<String>();
List<String> nonOrderedPostProcessorNames = new ArrayList<String>();
//按照优先级进行分类,放到对应的集合中
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else {
nonOrderedPostProcessorNames.add(ppName);
}
}
// 首先注册实现了PriorityOrdered接口的后置处理器
sortPostProcessors(beanFactory, priorityOrderedPostProcessors);
//添加到beanFactory的后置处理器集合中,
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
//其次,注册实现Ordered接口的后置处理器,注意,ordered越大,优先级越小。
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(beanFactory, orderedPostProcessors);
//添加到beanFactory的后置处理器集合中,
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// 现在,注册一些普通的后置处理器
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<BeanPostProcessor>();
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
//添加到beanFactory的后置处理器集合中,
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// 最后,重新注册内部后置处理器
sortPostProcessors(beanFactory, internalPostProcessors);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
以上就是spring对后置处理器的初始化过程,当初始完这些后,refresh()
方法中的finishBeanFactoryInitialization()
方法,就会继续初始化容器中所有的单例,非懒加载的bean对象,这些对象包含我们自定义的Controller
,Service
等,这些自定义对象就会按照上面后置处理器的处理逻辑,执行对应的postProcessBeforeInitialization()
和postProcessAfterInitialization()
方法。
结语
由于spring中的异步是通过实现了Ordered
接口的AsyncAnnotationBeanPostProcessor
处理的,定时任务是通过实现了Ordered
接口的ScheduledAnnotationBeanPostProcessor
处理的,二者都实现了Order
接口,属于同一优先级,由于同一优先级的后置处理器不能相互作用,然后在spring在初始化ScheduledAnnotationBeanPostProcessor
后置处理器时,发现某个bean依赖了这个service,导致service被提前加载了,此时实现Ordered
接口的后置处理器还没有放到BeanFactory
中,故异步功能失效了。