关于springboot:springboot2配置文件定义username内容失效问题探究

45次阅读

共计 3494 个字符,预计需要花费 9 分钟才能阅读完成。

前言

在敌人的我的项目有个自定义配置文件 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 的内容不是咱们想要的

排查


从跟踪的源码能够发现有个 systemProperties 配置排在 user.yml 后面。systemProperties 这是个啥货色,见名之意,这显著就是零碎属性配置。而 systemProperties 外面又有啥内容,咱们持续跟踪下


从源码能够看出 systemProperties 外面有个 key 为 user.name,value 为 Administrator。

从这边咱们能够看出咱们控制台打印进去的内容其实是 systemProperties 的内容。由此咱们能够推断出 当零碎变量和自定义配置变量都有一样的 key 时,将以零碎变量的值为准。

看到这边兴许有敌人说你这是在胡言乱语,就凭这个景象就得出这个论断。那好为了证实这个论断,咱们不得持续断点排查上来。不过在断点之前,咱们去 spring 官网溜溜,看有没有啥播种。进官网咱们能够看到有这么一段话

这段话的意思是 默认状况下,零碎属性优先于环境变量。因而,如果在调用 env.getProperty(“my-property”)的过程中在两个中央都同时设置了 my-property 属性,则零碎属性值“wins”并返回。请留神,属性值不会合并,而是会被后面的条目齐全笼罩。

看吧,官网它本人也这么说

如果咱们想要自定义的属性优于零碎属性,要怎么做


这段也是从官网截图来的,其意思是整个机制是可配置的。兴许您具备要集成到此搜寻中的自定义属性源。为此,实现并实例化您本人的 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 不一样就好。能少写代码就尽量少写

正文完
 0