概述
在学习Spring的过程中,出现一个问题,在.properties文件中设置userName=root无效,xml配置文件采用p:username="${userName}"的形式配置,每次spring容器启动之后,username属性还是我的系统的默认用户jwzhou,由于对spring源码不熟悉,只有一步一步调试,看看能不能找到属性设置无效的原因。
环境:
操作系统:win10
开发IDE:intellij idea
Spring版本:4.2.2
这里先把结论和解决方法放在前面,因为调试过程又长又混乱,且可以说是无用功
结论:自己配置无效的原因:默认情况下spring优先读取系统变量和环境变量来解析"${userName}"
解决方法:
思路1
userName改名为user或者其他不与环境变量重名的字符串
思路2
不采用
<context:property-placeholder
location="classpath:com/smart/placeholder/jdbc.properties"/>
而采用,类似下面的配置,这样就可以设置localOverride属性为true,从而使自己配置的userName覆盖环境变量的值。
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer" p:fileEncoding="utf-8" p:localOverride="true"> <property name="locations"> <list> <value>classpath:com/smart/placeholder/jdbc.properties</value> </list> </property> </bean>
调试过程:
1.启动spring的代码
2.进入ClassPathXmlApplicationContext构造方法之后,可以看到首先执行类的初始化代码块,这里不是我本次需要关注的代码。
3. 进入构造函数
4. super(parent);和setConfigLocations(configLocations);语句的含义都非常好理解,我们需要关注的是refresh方法,进入refresh方法
5.通过看书得知obtainFreshBeanFactory()方法负责将配置文件中的信息读取到Spring容器bean定义注册表中,因此重点关注这个方法的实现。
6. 进入refreshBeanFactory()方法,方法所在类
AbstractRefreshableApplicationContext
7. 进入loadBeanDefinitions(beanFactory)方法,方法所在类
AbstractXmlApplicationContext
8. 进入loadBeanDefinitions(beanDefinitionReader)方法,方法所在类
AbstractXmlApplicationContext
9. 进入reader.loadBeanDefinitions(configLocations),方法所在类
AbstractBeanDefinitionReader
此时可以看到通过变量窗口可以看到,locations数组长度为1,因此这里可以for循环里面的内容只会执行一次。
10. 进入loadBeanDefinitions(location),方法所在类
AbstractBeanDefinitionReader
11. 进入loadBeanDefinitions(resources),方法所在类
AbstractBeanDefinitionReader
查看变量窗口可以看到resoures数组长度为1,因此for循环只会执行一次
12. 进入loadBeanDefinitions(resource),方法所在类
XmlBeanDefinitionReader
13. 进入doLoadBeanDefinitions(inputSource, encodedResource.getResource()),方法所在类
XmlBeanDefinitionReader
14. 进入registerBeanDefinitions(doc, resource),方法所在类
XmlBeanDefinitionReader
15. 进入registerBeanDefinitions(doc, createReaderContext(resource)),方法所在类
DefaultBeanDefinitionDocumentReader
16. 进入doRegisterBeanDefinitions(root),方法所在类
DefaultBeanDefinitionDocumentReader
17. 进入parseBeanDefinitions(root, this.delegate),方法所在类
DefaultBeanDefinitionDocumentReader
关注ele变量的值,知道能够看到如下截图所示信息,也就是本文开头所说的userName属性设置,
DefaultBeanDefinitionDocumentReader
可以看到此时username还没有解析为jwzhou
DefaultBeanDefinitionDocumentReader
DefaultListableBeanFactory
此方法较长,关键代码见下面截图
可以看到,到目前为止,username属性,依然没有解析为jwzhou,我们继续往后走。
走走走走走啊走,走到九月九,
他乡没有烈酒,没有问候...
"解析成实际的值,也就是说,前面的工作,对找出配置没有生效完全是没有太大意义的,
那么我们只能继续看后面方法的代码。
说明在方法invokeBeanFactoryPostProcessors中进行了解析,下面重点追踪在这个方法里面beanFactory
的变化。
所在类:AbstractApplicationContext
不断往后走,定位到username改变的语句,见截图
23. 进入invokeBeanFactoryPostProcessors(priorityOrderedPostProcessors, beanFactory),
方法所在类:PostProcessorRegistrationDelegate,
24.进入postProcessor.postProcessBeanFactory(beanFactory),
方法所在类:PropertySourcesPlaceholderConfigurer
25. 进入processProperties(beanFactory, new PropertySourcesPropertyResolver
(this.propertySources)),
方法所在类:PropertySourcesPlaceholderConfigurer
visitor.visitBeanDefinition(bd),
方法所在类:BeanDefinitionVisitor
visitPropertyValues(beanDefinition.getPropertyValues()),
BeanDefinitionVisitor
resolveValue(pv.getValue())
BeanDefinitionVisitor
resolveStringValue((String) value)
BeanDefinitionVisitor
this.valueResolver.resolveStringValue(strVal)
PropertySourcesPlaceholderConfigurer
propertyResolver.resolveRequiredPlaceholders(strVal)
AbstractPropertyResolver
this.doResolvePlaceholders(text, this.strictHelper)
AbstractPropertyResolver
PropertyPlaceholderHelper
parseStringValue(value, placeholderResolver, new HashSet<String>())
PropertyPlaceholderHelper
placeholderResolver.resolvePlaceholder(placeholder)
方法所在类:
.......省略号。。。
由于类似的过程实在太多,下面直接放一些关键信息,不再逐步跟踪,
首先说结论,根据追踪,是由于环境变量中已经存在USERNAME这个环境变量,
所以会直接去读环境变量中的username,而且不论大小写,都会先转化为
大写,再去环境变量中找,就算写成UsErName也是一样配置无效,
转化成大写代码:
如截图所示,执行到特定步骤可以通过变量窗口看到spring框架从系统中读取的环境变量
spring框架获取环境变量的核心代码如图:
经过一系列的跟进,现在我们知道spring框架会读取环境变量,那么为什么不读取我自己配置的本地变量呢,查看PropertySourcesPlaceholderConfigurer类的api :
https://docs.spring.io/spring/docs/4.2.2.RELEASE/javadoc-api/index.html?org/springframework/beans/factory/config/PropertyPlaceholderConfigurer.html
,发现其实是否用本地文件配置覆盖环境变量是可以配置的,所以我们前面做的都是无用功,直接看文档看懂了就可以了,根本不需要一步一步调试。。。而且我配置的无效也是正常情况,是我自己不了解spring的处理逻辑罢了。
最后
以上就是大意夏天为你收集整理的查找spring配置文件设置userName属性无效的原因的全部内容,希望文章能够帮你解决查找spring配置文件设置userName属性无效的原因所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复