利用 Spring Boot 中的 @ConfigurationProperties,优雅绑定配置参数

使用 @Value(“${property}”) 注释注入配置属性有时会很麻烦,尤其是当你使用多个属性或你的数据是分层的时候。

Spring Boot 引入了一个可替换的方案 —— @ConfigurationProperties 来注入属性。

JavaBean 属性绑定

@Data
@ConfigurationProperties("my.service")
public class MyProperties {

    // 我们可以简单地用一个值初始化一个字段来定义一个默认值
    private boolean enabled = true;

    private InetAddress remoteAddress;

    private final Security security = new Security();

    @Data
    public static class Security {

        private String username;

        private String password;
        // 如果这个属性配置的话,默认是"USER"
        private List roles = new ArrayList<>(Collections.singleton("USER"));

    }
}

在配置文件中进行如下配置:

my:
  service:
    enabled: true
    remoteAddress: 127.0.0.1
    security:
     username: csx
     password: passwoed
     roles:
       - role1
       - role2

最后生成的 Bean 的属性如下:

{
  "enabled": true,
  "remoteAddress": "127.0.0.1",
  "security": {
    "username": "csx",
    "password": "passwoed",
    "roles": [
      "role1",
      "role2"
    ]
  }
}

以上的绑定当时需要提供默认的构造函数,以及get/setter方法。
并且不支持 JavaBean 中的静态成员变量的数据绑定

另外,@ConfigurationProperties 还有两个其他属性。

@ConfigurationProperties( value = "my.service",
                          ignoreInvalidFields = false,
                          ignoreUnknownFields = false)

ignoreInvalidFields:是否忽略非法值,比如将一个字符串 “foo” 赋值给 bool 值,不忽略的话会报启动异常。

ignoreUnknownFields:对于多余的配置是否会报异常。

构造函数绑定

有些情况下,我们需要绑定的 JavaBean 是不可变的(防止配置注入 Bean 以后,开发者在程序中错误地将配置改掉了)。这种情况下我们可以使用构造函数形式的绑定,只提供 getter 方法。

@Getter
@ConstructorBinding
@ConfigurationProperties("my.service")
public class MyProperties {

    private boolean enabled;
    private InetAddress remoteAddress;
    private final Security security;

    public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
        this.enabled = enabled;
        this.remoteAddress = remoteAddress;
        this.security = security;
    }

    @Getter
    public static class Security {

        private String username;
        private String password;
        private List roles;

        public Security(String username, String password, @DefaultValue("USER") List roles) {
            this.username = username;
            this.password = password;
            this.roles = roles;
        }
    }
}

@DefaultValue 可以指定默认值。

使用构造函数绑定的方式,只能 @EnableConfigurationProperties 或者 @ConfigurationPropertiesScan 的方式激活 Bean。而不能使用 @Component、@Bean 或者 @Import 的方式进行数据绑定。

如果你的类有多个构造函数,可以直接指定使用哪个。

@ConstructorBinding
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
    this.enabled = enabled;
    this.remoteAddress = remoteAddress;
    this.security = security;
}

激活方式

方式一:添加 @Component 注解

上面的方式需要保证 MyProperties 能被 Spring 扫到。

@Data
@Component
@ConfigurationProperties("my.service")
public class MyProperties {

}

方式二:通过 @Bean 方法

@Configuration
public class ServiceConfig {

    @Bean
    public MyProperties myProperties(){
        return new MyProperties();
    }
}

方式三:@EnableConfigurationProperties(推荐)

@Configuration
@EnableConfigurationProperties(MyProperties.class)
public class ServiceConfig {

}

方式四:@ConfigurationPropertiesScan

@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {

}

怎么使用

我们通过配置在 Spring 容器中生成了配置 Bean,那么需要怎么使用他们呢?

@Service
public class MyService {
    // 依赖注入
    @Autowired
    private MyProperties properties;

    public void service(){
        System.out.println(properties.getRemoteAddress());
    }

}

@Service
public class MyService {

    private MyProperties properties;
    // 通过构造函数注入,一般推荐这种方式
    public MyService(MyProperties properties) {
        this.properties = properties;
    }

    public void service(){
        System.out.println(properties.getRemoteAddress());
    }

}

给第三方类绑定值

假如某些类不是你自己开发的,你也想使用 @ConfigurationProperties 的方式给他绑定值,那么可以进行下面的方式进行配置。

@Configuration(proxyBeanMethods = false)
public class ThirdPartyConfiguration {

    @Bean
    @ConfigurationProperties(prefix = "another")
    public AnotherComponent anotherComponent() {
        return new AnotherComponent();
    }

}

宽松绑定原则(Relaxed Binding)

所谓的宽松绑定原则是指:并不是 JavaBean 中的属性必须要和配置文件中的一致才能绑定数据,context-path 也能绑定到 contextPath 属性上。下面举个列子:

@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {

    private String firstName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

}

下面的几种方式,都能将配置文件或者环境变量中的值绑定到 firstName 上。

形式 使用场景 my.main-project.person.first-name

推荐使用在 .properties

and .yml

files. my.main-project.person.firstName

Standard camel case syntax. my.main-project.person.first_name

推荐使用在 .properties

and .yml

files. MY_MAINPROJECT_PERSON_FIRSTNAME

推荐使用在系统环境变量读取配置时使用

和 @Value 对比

@Value 是 Spring Framework 中的注解,而 @ConfigurationProperties 是在 Spring Boot 中引入的。

利用 Spring Boot 中的 @ConfigurationProperties,优雅绑定配置参数

参考

Original: https://www.cnblogs.com/54chensongxia/p/15250479.html
Author: 程序员自由之路
Title: 利用 Spring Boot 中的 @ConfigurationProperties,优雅绑定配置参数

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/541898/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

  • Random在高并发下的缺陷以及JUC对其的优化

    Random可以说是每个开发都知道,而且都用的很6的类,如果你说,你没有用过Random,也不知道Random是什么鬼,那么你也不会来到这个技术类型的社区,也看不到我的博客了。但并…

    Java 2023年6月5日
    097
  • 编译实战 | 手摸手教你在Windows环境下运行Redis6.x

    原创:微信公众号 &#x7801;&#x519C;&#x53C2;&#x4E0A;,欢迎分享,转载请保留出处。 哈喽大家好啊,我是没事就愿意瞎捣鼓的…

    Java 2023年6月5日
    0100
  • Java字节码技术 static、final、volatile、synchronized关键字的字节码体现 转

    出处: static、final、volatile关键字 static:static修饰的变量被所有类实例共享,静态变量在其所在类被加载时进行初始化,静态方法中不能引用非静态变量或…

    Java 2023年5月29日
    080
  • 设计模式—建造者模式

    类型:创建型 目的:创建对象时,提升属性设置的 灵活性。 灵活性 类中定义了大量属性时,通常为了创建对象时属性初始设置的便利随之定义大量的构造方法。为了既不定义过多的构造方法,又保…

    Java 2023年6月7日
    076
  • 居然要周末加班才解决这个问题

    摘要 万万没想到,最近的一个任务居然在一周没有解决,弄得周六在家忙了一天,还没完成,直到周日早上灵光一闪,才完成了。坦白讲,我已经好久没有过这种体验了,被一个技术问题困扰了好几天,…

    Java 2023年6月8日
    095
  • [转java发送http的get、post请求]

    Http请求类 package wzh.Http; import java.io.BufferedReader; import java.io.IOException; impor…

    Java 2023年5月29日
    095
  • Scala中for循环的使用

    Scala中的for循环: 一.第一种实现方式:(生成器表达方式) 二.使用until生成1到10范围内的数据,包左包右(相当于10-1) 三.在第一种实现方式的基础上加上步长限制…

    Java 2023年6月9日
    065
  • Win10搭建Jenkins部署Java项目(本机和远程Win10部署)

    一、前言&背景 二、环境准备 三、插件安装 四、全局配置 Maven JDK Git Maven 五、新建项目并配置 新建项目 配置 1、Discard old build…

    Java 2023年6月9日
    0122
  • Spring5

    Spring概述 1、Spring是轻量级开源JavaEE框架 2、Spring可以解决企业应用开发的复杂性 3、组成核心IOC、Aop IOC:控制反转,把创建对象过程交给Spr…

    Java 2023年6月13日
    067
  • MySQL四:InnoDB的存储结构

    转载~ 「MySQL存储引擎最大的特点就是【插件化】,可以根据自己的需求使用不同的存储引擎,innodb存储引擎支持行级锁以及事务特性,也是多种场合使用较多的存储引擎。」 当官方的…

    Java 2023年6月8日
    094
  • linux-0.11分析:进程初始化函数init(),第二部分(void) open(“/dev/tty0”,O_RDWR,0),第十三篇随笔

    第二部分, (void) open(“/dev/tty0”,O_RDWR,0); 参考 [github这个博主的 厉害][ https://github.com/sunym1993…

    Java 2023年6月16日
    0109
  • 分治思维谈管道模式

    本文摘自我的公众号:【陶朱公Boy】。也欢迎大家关注我的公众号,里面有很多优质的文章包括架构、面试、学习方法论等。 文章:《分治思维谈管道模式》 回复关键字” pipe…

    Java 2023年6月15日
    072
  • Mybatis Mapper动态代理方式 typeAliases 别名的使用

    目录结构及配置文件与原始dao方法相比更简便 只需一个UserMapper的接口,放在一起的配置文件,配置文件中namespace的地址确定jdk动态代理的对象

    Java 2023年5月30日
    081
  • Linux自动备份MySQL、删除过期备份

    背景:阿里云服务器,只有一个数据库 需求:每天凌晨备份数据库、超过7天自动删除 方法: 一、新建执行脚本(/home/dbback/bkmscm.sh) 二、授予脚本权限 chmo…

    Java 2023年6月8日
    078
  • JavaFx 模拟键盘和鼠标事件

    模拟键盘事件 可实现按键的模拟,包含快捷键 模拟按下 ctrl+v示例代码: val robot = Robot() robot.keyPress(KeyEvent.VK_CONT…

    Java 2023年6月13日
    086
  • Spring Boot 面试问题

    说一说你对Spring Boot的理解 名词解释: Spring Boot 基于 Spring 开发, Spirng Boot 本身并 不提供 Spring 框架的核心特性以及扩展…

    Java 2023年6月7日
    079
亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球