springboot在applicationproperties.xml中配置的user.name失效问题
先复现一下问题吧:
在springboot中,将注解@ConfigurationProperties(prefix="".....)添加到bean上,可以在bean生成的时候将application.properties中预定义的值注入到bean中,如下图:
这是在Bean中添加的注解
这是application.properties中添加的属性
通过写一个简单的HelloBoy控制器将BoyNextDoor注入,分配路径:
启动项目,呼叫boy:http://localhost:8080/BoyNextDoor
看,我们的banana君出来找你了呢 -_-...
问题来了,当我们将applications.properties中的属性变更为user之后会怎么样呢.
同时得修改bean上的注解
当当当当.......
BiLi好像不在家呢, 怎么回事呢??
又是谁给出的BiLiIsNotHere呢?
答案在这里
原来我的windows登陆名叫BiLiIsNotHere, 在application.properties中的user.name失效了..
为什么呢?我也想知道啊,接下来就是苦逼的找源码了时间了,明天再更...
想要知道为什么user.name会被覆盖就得去看源码了,从项目的启动到结果的输出可以看做一条线,我们从任何一点切入都能捋到线的两头,我们先找到其中的一点,
最明显的就是@ConfigurationProperties注解,我们看一下这个注解。
并没有太多有用的信息,所谓物以类聚,那么我们到注解所在的包内查看如下:
根据字面意思来看,ConfigurationPropertiesBinder为配置变量绑定器,不点他点谁呢,idea告诉我们哪里不会点哪里,我们点进去看能看到有个方法叫bind(),
这个方法做的事情大概就是从target中获取到所有的@ConfigurationProperties注解,然后绑定到target中,
annotation.prefix();获取到的就是我们在@ConfigurationProperties中传入的值“user";
然后我们跟踪bind(annotation.prefix(),target,bindHandler)方法可以找到如下代码
findProperty(name, context);方法就是我们寻求的重点,其中name是注解中的prefix传入的值,既为我们传入的字符串"user",context为Binder的一个内部类,在bind过程中初始化的,如下:
这个类并没有做特殊处理,接下来看findProperty方法
这里对context中的sources进行了遍历获取预定义的user的值,既然我们的user.name被覆盖了,我们就看下这个Souces是什么东西,
为什么从这里面取到的值会覆盖我们预定义的值
更新中。。。。。。
代码层面上我就不继续追了(其实已经差不多追完了), 在spring framework文档中找到了相关说明:
(大意是“属性的搜索是分层级的, 默认情况下, 系统属性(system properties)比环境变量的优先级高, 因此, 如果‘my-property’属性同时设置在两个地方, 并通过env.getProperty(‘my-property’)方法获取该属性时, 将会返回系统属性. 注意各个属性值不会合并, 而是完全地被优先级高的属性覆盖.”) , 通过这点我们就可以知道属性的获取不是通过合并而是通过优先级的方式, 排在最前面的属性最先获取.
在本文的例子中, 各个属性的排序如下
可见systemPropertyes在我们自定义的属性之前. 如果要改变这个顺序可以在bean初始化之前获取applicationContext中的environment然后手动改变propertySourceList里面PropertySource的顺序( 硬核编码... ).
完.