问题描述
问题描述:在配置类中使用@PropertySource引入了.properties文件,但是使用@Value注入时,结果竟然null。
郁闷了一上午。
在Spring与MyBatis整合时,需要注入MyBatis的自动扫描配置类MapperScannerConfigurer的Bean
我用的是纯注解的方式,所以为了图方便,将DataSource的注入与MapperScannerConfigurer的注入写在了同一个配置类中,像这样:
@Configuration
@PropertySource("classpath:jdbc.properties")
public class MyBatisConfig{
@Value("${jdbc.url}")
private String url;
@Value(("${jdbc.driver}"))
private String driver;
@Value(("${jdbc.username}"))
private String username;
@Value("${jdbc.password}")
private String password;
@Bean
public DataSource dataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setUrl(url);
ds.setDriverClassName(driver);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource ds) {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(ds);
factoryBean.setTypeAliasesPackage("com.liumingkai.domain");
return factoryBean;
}
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurer scannerConfigurer = new MapperScannerConfigurer();
scannerConfigurer.setBasePackage("com.liumingkai.dao");
return scannerConfigurer;
}
}
以上代码在运行时,利用@Value读取出来的数据是null,就导致无法数据源错误,无法连接数据库。
然后就在数据源身上DEBUG,一上午无济于事,郁闷死了。
然后打算一步一步重新做,看到哪一步是导致@Value无效的,最终发现:当我注入了MapperScannerConfigurer时,会导致@Value的值为null。
依次为突破点,在网上搜索到了这个类似的问题。
解决方案
就是不要将DataSource注入与MapperScannerConfigurer注入写在同一个配置类中。
将DataSource注入的代码写在JdbcConfig.java中,将SqlSessionFactoryBean和MapperScannerConfigurer这两个Bean的注入放在MyBatisConfig.java中
然后问题就解决了。
像这样:
原理分析
MapperScannerConfigurer的初始化要优先于Property属性的读取,由于配置类中使用了@Bean来将MapperScannerConfigurer提供出去,所以此配置类提前初始化,但是此时Property的还没有完成读取配置文件,就导致@Value的值是null。
将DataSource的注入与MapperScannerConfigurer分开后,MapperScannerConfigurer的提前初始化就不会影响到Property的读取,成功设置DataSource
巨人的肩膀
参考的文章
spring+mybatis使用MapperScannerConfigurer引起的PropertyPlaceholderConfigurer无效问题-蒲公英云
遇到的坑之MapperScannerConfigurer执行时机 遇到的坑之MapperScannerConfigure