由于不想在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实现了BeanDefinitionRegistryPostProcessorpublic class MapperScannerConfigurer implements BeanDefinitionRegistryPostProcessor;//PropertyPlaceholderConfigurer实现了BeanFactoryPostProcessorpublic 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。