由于不想在xml里面重复繁琐的配置bean,所以使用MapperScannerConfigurer来扫描包自动生成实例交给spring管理。但是却发现取不到PropertyPlaceholderConfigurer里面的值导致初始化datasource失败。
网上查阅发现只要修改SqlSessionFactoryBean的id不为sqlSessionFactory就行,说如果取名sqlSessionFactory就会触发dataSource提前初始化,但是为什么会提前,并没有相关解释。
现状是datasource里面的配置没有替换掉所以初始化失败,所以我们要先看看配置是啥时候被替换的 。我们先看看spring初始化的过程(AbstractApplicationContext):
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
再来看看这几个类的关系:
//MapperScannerConfigurer实现了BeanDefinitionRegistryPostProcessor
public class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor;
//PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessor
public class PropertyPlaceholderConfigurer extends PlaceholderConfigurerSupport;
public abstract class PlaceholderConfigurerSupport extends PropertyResourceConfigurer;
public abstract class PropertyResourceConfigurer implements BeanFactoryPostProcessor;
public interface BeanDefinitionRegistryPostProcessor extends BeanFactoryPostProcessor;
那我们需要来看看invokeBeanFactoryPostProcessors(beanFactory),难道是先替换的属性值,再注册的BeanDefinition?
//other codes...
invokeBeanDefinitionRegistryPostProcessors(orderedPostProcessors, registry);
//other codes...
invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory);
显然不可能是顺序问题,那在看看报错信息,从autowiredByName出现问题。
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByName(AbstractAutowireCapableBeanFactory.java:1244) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1194) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543) ~[spring-beans-4.3.2.RELEASE.jar:4.3.2.RELEASE]
... 39 common frames omitted
protected void autowireByName(
String beanName, AbstractBeanDefinition mbd, BeanWrapper bw, MutablePropertyValues pvs) {
String[] propertyNames = unsatisfiedNonSimpleProperties(mbd, bw);
//propertyNames为bean可能需要注入的属性
//在MapperScannerConfigurer中,有sqlSessionFactory,nameGenerator等
for (String propertyName : propertyNames) {
//重点来了,如果SqlSessionFactoryBean取名sqlSessionFactory,那么容器中将包含这个bean的定义
//那么SqlSessionFactoryBean将会初始化,而如果SqlSessionFactoryBean里面的Datasource也取名datasource
//那么SqlSessionFactoryBean初始化也会触发Datasource出事化,而此时还没走到配置值替换这个阶段
if (containsBean(propertyName)) {
Object bean = getBean(propertyName);
pvs.add(propertyName, bean);
registerDependentBean(propertyName, beanName);
else {
}
}
}
所以解决方案挺多的,把autowired by name去掉,SqlSessionFactoryBean不取名sqlSessionFactory,Datasource不取名datasource。