前言
这次问题排查比较特殊,涉及到公司使用的统一配置中间件,其大致原理是:通过继承AutowiredAnnotationBeanPostProcessor接口(其实现了InstantiationAwareBeanPostProcessor接口,顺序方面,是实现的PriorityOrdered接口),覆盖postProcessPropertyValues方法,实现动态配置(开关、动态改变日志级别等)。而在该方法中,为了获取该中间件自己的配置类(假设为Config.class),调用了applicationContext.getBean(Config.class)。我们问题的根源即出在这里。
transactional注解的实现原理
由切面实现,相关advisor为TransactionAttributeSourceAdvisor,而spring负责管理切面的BeanPostProcessor为InfrastructureAdvisorAutoProxyCreator,它的顺序接口是实现的Ordered。
问题分析
首先来看refresh()中registerBeanPostProcessors()方法的节选:
/**
* Instantiate and invoke all registered BeanPostProcessor beans,
* respecting explicit order if given.
* <p>Must be called before any instantiation of application beans.
*/
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);
//。。。略去无关部分
// First, register the BeanPostProcessors that implement PriorityOrdered.
OrderComparator.sort(priorityOrderedPostProcessors);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implement 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);
}
}
//。。。略去
}
总结: 问题根本原因在于,在实现了PriorityOrdered的PostBeanProcessor中调用applicationContext.getBean(Class),导致通过setter设置objectType的factoryBean初始化提前。可以通过构造器注入的方式避免该问题。