返回

Spring @ConfigurationProperties —— 从配置原理到手把手带你实现「指定前缀」获取属性

后端

在这个快节奏、敏捷迭代的时代,Spring已经成为Java编程领域不可忽视的“香饽饽”。从接触它开始,就伴随着我们进行项目开发。而在使用它的过程中,我们经常会遇到需要从配置文件中获取配置属性的情况。例如:

  • 当发送电子邮件时,我们需要获取收发件人及邮件服务器的地址和端口号。
  • 当访问数据库时,我们需要获取数据库的URL、用户名和密码。

对于上述这些常见的需求,Spring框架早已贴心地为我们准备好了@ConfigurationProperties,如此一来就可以直接通过代码来获取配置属性,这样无疑就减少了很大的人工操作和程序的冗余度。这岂不妙哉?那么,我们马上开始吧!

一切从最简单的开始:聊一聊 @ConfigurationProperties 的原理

直奔主题:所谓@ConfigurationProperties,其实就是通过在你的 JavaBean 上添加此注解,允许你将配置属性绑定到你 Bean 的字段上。这么说可能太理论化了,先抛出一个灵魂拷问:“如果你是 @ConfigurationProperties,那么你将完成怎样的工作呢?”

public class MyBean {

    private String name;
    private int age;

    // 填写 @ConfigurationProperties 注解,指定其前缀为 "mybean"
    @ConfigurationProperties(prefix = "mybean")

    // 获取或设置 name
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 获取或设置 age
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

所以@ConfigurationProperties 所做的工作就是:根据你配置的前缀,从 配置文件(此处特指 application.properties 和 application.yml)或环境变量中找到相应的前缀,并且将找到的值赋给你的 JavaBean 的字段。

【手把手教学环节】如何使用 Spring Boot 优雅获取配置属性

搭建好环境之后,我们就开始撸代码吧。话不多说,直接放代码!

1. 配置配置文件

首先,我们需要在配置文件中定义一些配置属性:

# application.yml
mybean:
  name: 小明
  age: 18

2. 新建一个 JavaBean

@ConfigurationProperties(prefix = "mybean")
public class MyBean {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "MyBean{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

3. 注册 Bean

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public MyBean myBean() {
        return new MyBean();
    }
}

4. 获取配置属性

现在,我们就可以通过以下方式获取配置属性:

@Autowired
private MyBean myBean;

public static void main(String[] args) {
    // 输出 myBean 的值
    System.out.println(myBean);
}

输出结果:

MyBean{name='小明', age=18}

至此,我们已经成功地使用了 Spring Boot 来获取配置属性。

核心揭秘:源代码 带你探秘 ConfigurationProperties

@Target({ElementType.TYPE, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationProperties {

    /**
     * The prefix that properties will match if specified.
     * <p>Default is an empty string: "", which matches any property.
     * @return the prefix string
     */
    String prefix() default "";

    /**
     * Whether to ignore unknown properties.
     * <p>Default is {@code true}.
     * @return {@code true} if unknown properties should be ignored
     */
    boolean ignoreUnknownFields() default true;

    /**
     * Whether to ignore invalid properties.
     * <p>Default is {@code false}.
     * @return {@code true} if invalid properties should be ignored
     * @since 2.1
     */
    boolean ignoreInvalidFields() default false;

    /**
     * The placeholders to resolve in ${...} expressions within
     * the configuration properties.
     * <p>Default is to resolve placeholders against system properties,
     * environment variables and Spring's {@link PropertySources}.
     * @return the list of placeholder resolvers
     * @since 2.2
     */
    PlaceholderResolver[] resolvers() default {};

}

从源码中可以看出,@ConfigurationProperties 注解有三个主要参数:

  • prefix: 指定属性的前缀,如果不指定,则匹配所有属性。
  • ignoreUnknownFields: 是否忽略未知属性,默认值为 true。
  • ignoreInvalidFields: 是否忽略无效属性,默认值为 false。

我们还能做出哪些扩展?

1. 自定义 Bean 注解

有时候,我们希望通过自定义注解来达到同样的效果,这该如何实现呢?此时,我们可以使用 @PropertySource 注解来实现:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@PropertySource("classpath:my-properties.properties")
public @interface MyProperties {

    String prefix() default "";

    boolean ignoreUnknownFields() default true;

    boolean ignoreInvalidFields() default false;

}

2. 自定义属性转换器

在有些情况下,我们可能需要对属性进行一些转换,比如将字符串转换为日期或数字。我们可以使用 @ConfigurationPropertiesBinding 注解来实现:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ConfigurationPropertiesBinding {

    Class<? extends PropertySourcesPropertyResolver> resolver() default PropertySourcesPropertyResolver.class;

    boolean ignoreInvalidFields() default false;

    boolean ignoreNestedProperties() default false;

}

上面简单举了几个例子,如果你有更多的创意,可以进一步去探索。Spring Boot 中的很多功能都是基于扩展实现的,如果你能熟练掌握这些扩展方式,那么恭喜你,你已经在 Spring Boot 的道路上迈出了一大步!

最后结语:不忘总结,牢记于心

  1. @ConfigurationProperties 注解用于从配置文件或环境变量中获取配置属性。
  2. @ConfigurationProperties 注解有三个主要参数:prefix、ignoreUnknownFields 和 ignoreInvalidFields。
  3. 我们还可以通过自定义 Bean 注解或自定义属性转换器来扩展 @ConfigurationProperties 注解的功能。