前提
1.开启了byName自动注入
2.定义了PropertySourcesPlaceholderConfigurer
,去解析配置。
3.含有id="sqlSessionFactory"
的SqlSessionFactory
4.定义了MapperScannerConfigurer
,在其属性sqlSessionFactory
中的dataSource
属性中使用了${username}
、${password}
等。
原因
-
MapperScannerConfigurer 是一个BeanDefinitionRegistryPostProcessor,它是
BeanFactoryPostProcessor
的实现类。 -
PropertySourcesPlaceholderConfigurer是一个
BeanFactoryPostProcessor
的实现类。 -
MapperScannerConfigurer 在 PropertySourcesPlaceholderConfigurer 之前被实例化。
3.1. 这是因为它们会在Spring的refresh
->invokeBeanFactoryPostProcessors(beanFactory)
被调用。 而顺序是 先注册BeanDefinitionFactoryProcessor
,再注册BeanFactoryPostProcessor
。 -
MapperScannerConfigurer优先实例化的时候,开启了
default-autowire="byName"
会连同属性sqlSessionFactory一起初始化,并造成dataSource初始化, 那么${username}
被提前设置到dataSource中的username
属性中,但此时PropertySourcesPlaceholderConfigurer还未生成实例,更没有替换${username}
,导致错误!
4.1 开启default-autowire="byName"
自动注入后,会解析出需要"sqlSessionFactory"依赖,并提前初始化。
解决
由于无法改变MapperScannerConfigurer与PropertySourcesPlaceholderConfigurer的getBean初始化顺序。
那么避免sqlSessionFactory的属性提前初始化。
1.去掉default-autowire="byName"
2.改变sqlSessionFactory的id。(未验证) (TODO)
常见报错配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:jaxws="http://cxf.apache.org/jaxws" xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"
default-autowire="byName">
<context:property-placeholder location="conf/*.properties"/>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" lazy-init="true">
<property name="driverClassName" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="mapperLocations" value="mapper/*.xml"/>
<property name="dataSource" ref="dataSource"/>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.yanmushi.**.mapper"/>
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
</beans>
参考
https://my.oschina.net/u/161336/blog/1830816