springboot2配置文件定义${user.name}内容失效问题探究

Easter79
• 阅读 562

前言

在朋友的项目有个自定义配置文件user.yml,其内容如下

user:
  userId: 1
  name: 张三
  email: zhangsan@qq.com

其映射实体内容为如下

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@PropertySource(value = "user.yml",encoding = "utf-8",factory = CustomYmlPropertySourceFactory.class)
@ConfigurationProperties(prefix = "user")
@Configuration
public class User {

    private String name;

    private Long userId;

    private String email;
}

项目启动后,输出的user内容为

User(name=Administrator, userId=1, email=zhangsan@qq.com)

很明显name的内容不是我们想要的

排查

springboot2配置文件定义${user.name}内容失效问题探究 从跟踪的源码可以发现有个systemProperties配置排在user.yml前面。systemProperties这是个啥东西,见名之意,这明显就是系统属性配置。而systemProperties里面又有啥内容,我们继续跟踪下 springboot2配置文件定义${user.name}内容失效问题探究 springboot2配置文件定义${user.name}内容失效问题探究 从源码可以看出systemProperties里面有个key为user.name,value为Administrator。

从这边我们可以看出我们控制台打印出来的内容其实是systemProperties的内容。由此我们可以推断出当系统变量和自定义配置变量都有一样的key时,将以系统变量的值为准。

看到这边也许有朋友说你这是在胡说八道,就凭这个现象就得出这个结论。那好为了证明这个结论,我们不得继续断点排查下去。不过在断点之前,我们去spring官网溜溜,看有没有啥收获。进官网我们可以看到有这么一段话 springboot2配置文件定义${user.name}内容失效问题探究 这段话的意思是默认情况下,系统属性优先于环境变量。 因此,如果在调用env.getProperty(“ my-property”)的过程中在两个地方都同时设置了my-property属性,则系统属性值“ wins”并返回。 请注意,属性值不会合并,而是会被前面的条目完全覆盖。

看吧,官网它自己也这么说

如果我们想要自定义的属性优于系统属性,要怎么做

springboot2配置文件定义${user.name}内容失效问题探究 这段也是从官网截图来的,其意思是整个机制是可配置的。 也许您具有要集成到此搜索中的自定义属性源。 为此,实现并实例化您自己的PropertySource并将其添加到当前环境的PropertySources集中

ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());

这个是官方解法。

我这边在提供2种解法。

  • bean初始化之前,修改属性文件加载顺序
  • 在bean初始化后,变更bean的属性值

其实现代码如下

ntBeanFactoryPostProcesser implements BeanFactoryPostProcessor, ApplicationContextAware, BeanPostProcessor {

    private ApplicationContext applicationContext;

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        //方法三:在bean初始化后,变更bean的属性值
//        if("user".equals(beanName)){
//            User user = (User)bean;
//            System.out.println("----------------before---------------------");
//            System.out.println("user-->"+user);
//            System.out.println("----------------after---------------------");
//            String propertySourceName = "user.yml";
//            PropertySource propertySource = getPropertySource(propertySourceName);
//            if(!ObjectUtils.isEmpty(propertySource)){
//               user.setName(String.valueOf(propertySource.getProperty("user.name")));
//            }
//            System.out.println("user-->"+user);
//
//        }
        return bean;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
        printPropertySourceNames();
       String propertySourceName = "user.yml";
        PropertySource propertySource = getPropertySource(propertySourceName);
        if(!ObjectUtils.isEmpty(propertySource)){
            //方法一 bean初始化之前,修改属性文件加载顺序
            getEnvironment().getPropertySources().remove(propertySourceName);
            getEnvironment().getPropertySources().addFirst(propertySource);
        }

        // 方法二 新增一个PropertySource,并把他的加载顺序置为第一位
//        Map<String, Object> propertiesSource = new HashMap<>();
//        propertiesSource.put("user.name", "张三");
//        PropertySource newPropertySource = new MapPropertySource("newPropertySource", propertiesSource);
//        getEnvironment().getPropertySources().addFirst(newPropertySource);





    }

    private PropertySource getPropertySource(String propertySourceName){
        return getEnvironment().getPropertySources().get(propertySourceName);
    }

    private AbstractEnvironment getEnvironment(){
        return (AbstractEnvironment)applicationContext.getEnvironment();
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }


    private void printPropertySourceNames(){
        getEnvironment().getPropertySources().stream().forEach(p-> System.out.println(p.getName()));
    }



}

改完后,我们看下控制台此时输出的内容为

User(name=张三, userId=1, email=zhangsan@qq.com)

总结

其实要想自定义文件属性值不和系统变量的值产生冲突,最快捷的方法,就是让自定义文件属性的key和系统变量的key不一样就好。能少写代码就尽量少写

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
5个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
11个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k