问题背景:
- 这个问题排查了有2-3天,尝试了各种组合配置没有解决。最后还是查资料看别人的解决经验解决了。
问题现象:
- 一个17年的老项目继续开发,其中是spring+mybatis+ibatis组合,基于一个更早12年的ibatis老项目开发的(开源otter)。把spring的配置datasource的xml文件中datasrouce的driver,url,username,password改成application.properties中使用spring的PropertyPlaceholderConfigurer来进行配置文件读取值替换。但是怎么配都提示变量无法解析。查了很多材料,都是说PropertyPlaceholderConfigurer的用法和spring怎么配外部配置文件的。没有关键信息、
- 如果不用配置文件,直接写死是没问题的。使用xml中的properties属性也不行。
- 错误如下图:
- 怀疑与bean的初始化顺序有关,也就是datasource的bean初始化的时候还没有进行配置文件解析,PropertyPlaceholderConfigurer还没生效。
主要探索过程:
- 首先想到占位符的原理,参考该文章:
- 深入Spring Boot:那些注入不了的Spring占位符(${}表达式)
- https://blog.csdn.net/hengyunabc/article/details/75453307
- 与该文章现象一致,并提示:结合上面的Spring的生命周期,如果Bean的创建和使用在PropertySourcesPlaceholderConfigurer之前,那么就有可能出现占位符没有被处理的情况。并提出:Mybatis 的 MapperScannerConfigurer引起的占位符没有处理,查出该类导致了datasource的bean提前初始化,在配置还没解析前。所以报错。
- 大概原因就应该是这个。
- 继续探索:
- 从配置文件PropertySourcesPlaceholderConfigurer何时生效继续看,找出另一个文章:关于dubbo 占位符无法解析问题
- https://blog.csdn.net/su20145104009/article/details/105160565
- 该文提出思路:此时,只有一种想法,难道该 bean 的初始化早于 PropertySourcesPlaceholderConfigurer 的替换?也就是说,RegistryConfig 被提前初始化了
- 该文提出解决方法:也关注到了:注册MapperScannerConfigurer的bean被提前初始化的问题
- 但是改了其中的参数,还是没解决我的问题。但是排查问题过程更清晰。
- 继续探索:
- 在bing搜索:PropertyPlaceholderConfigurer无法注入,偶然得到一个文章:
- PropertyPlaceholderConfigurer模式从properties加载数据源参数失败的解决方案
- https://www.iteye.com/blog/yjy110-1882876
- 报错类似,同时也将问题关注到了:一开始怀疑是spring版本问题,就搜索了一下“spring3 PropertyPlaceholderConfigurer”,结果发现还真有类似的提问,只不过比我问的更准确,一下就把问题定位到了问题的根源-------mybatis下的MapperScannerConfigurer扫描模式造成了bean的加载顺序改变从而使得PropertyPlaceholderConfigurer无法正常加载。
改用sqlSessionFactoryBeanName注入就没有问题(不要使用sqlSessionFactory属性注入,使用sqlSessionFactoryBeanName注入),因为这时不会立即初始化sqlSessionFactory,传入的只是名字,非bean,所以不会引发提前初始化问题。。 - 该文给出的MapperScannerConfigurer的sqlSessionFactory注入方式也没解决问题,不过已经可以确认问题就是这个。
- 文中给出1个链接:https://www.oschina.net/question/188964_32305?sort=default&p=3
- spring3.0.6 使用context:property-placeholder载不进属性
- 该问题下面好多人遇到了类似问题,有人提出关键点:
- 两种解决办法:
1. <!-- mybatis文件配置,扫描所有mapper文件 -->
<!-- configLocation为mybatis属性 mapperLocations为所有mapper -->
<bean id="mb-sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"
p:dataSource-ref="dataSource" p:configLocation="classpath:web/sqlmap/mybatis-config.xml"
p:mapperLocations="classpath:web/sqlmap/mapper/*.xml" />
<!-- spring与mybatis整合配置,扫描所有dao -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"p:basePackage="com.jiezhibar.candy.web.dao"
p:sqlSessionFactoryBeanName="mb-sqlSessionFactory" />
即:sqlSessionFactoryBeanName的值写成非sqlSessionFactory
2、xml 头部将 default-autowire="byName"去掉
-
发现我的项目里确实有default-autowire="byName"去掉后圆满解决,datasource的参数可以正常注入了。
-
dubbo consumer读取配置文件无法解析问题
- 参考:https://blog.csdn.net/u011494923/article/details/88076096
- dubbo的xml中${}不生效获取不到变量
-
参考:spring配置文件:Could not resolve placeholder
-
参考:PropertySourcesPlaceholderConfigurer读取配置文件的坑
- https://blog.csdn.net/leaves_story/article/details/89672050
- 该文说明:Spring容器仅允许最多定义一个PropertyPlaceholderConfigurer(或),其余的会被Spring忽略掉。
-
参考:Spring 在xml中引入properties文件方式和问题
-
参考:Spring 常用的两种PropertyPlaceholderConfigurer