前提
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