如何在Spring Boot中使用@ConfigurationProperties注解?

97 阅读7分钟

在 Spring Boot 中,​​@ConfigurationProperties​​ 注解的核心作用是将配置文件(如​application.properties​/​​application.yml​​​)中的属性批量绑定到 Java 实体类,避免手动通过​@Value​​ 逐个注入属性,尤其适合处理多属性、层级化的配置场景(如数据库连接、第三方 API 配置等)。

下面分 基础使用步骤、进阶场景(层级配置、松散绑定、校验)、常见问题 三部分,详细讲解其用法:

一、基础使用步骤(核心流程)

步骤 1:创建配置属性实体类

定义一个 Java 类,用 ​​@ConfigurationProperties​​ 指定配置文件中的属性前缀(如 ​​spring.datasource​​、​​custom.oss​​),并提供属性的 ​​getter/setter​​ 方法(Spring 需通过 setter 注入值)。

示例:绑定 OSS 存储配置

假设配置文件中需要配置阿里云 OSS 的相关信息,实体类如下:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

// 1. 标注注解:prefix 指定配置文件中的属性前缀(必须与配置文件一致)
@ConfigurationProperties(prefix = "custom.oss")
// 2. 注册为 Spring Bean(三种方式选一种即可,下文详细说明)
@Component
public class OssProperties {
    // 配置文件中的属性名:custom.oss.endpoint
    private String endpoint;
    // 配置文件中的属性名:custom.oss.access-key
    private String accessKey;
    // 配置文件中的属性名:custom.oss.secret-key
    private String secretKey;
    // 配置文件中的属性名:custom.oss.bucket-name
    private String bucketName;

    // 3. 必须提供 getter 和 setter 方法(Spring 自动注入值)
    public String getEndpoint() {
        return endpoint;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public String getAccessKey() {
        return accessKey;
    }

    public void setAccessKey(String accessKey) {
        this.accessKey = accessKey;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }
}

步骤 2:在配置文件中添加对应属性

在 ​​application.yml​​(推荐,层级清晰)或 ​​application.properties​​ 中,添加与 ​​prefix​​ 匹配的属性:

方式 1:application.yml(推荐)
custom:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    access-key: LTAI4Gxxxxxxx
    secret-key: 8Zxxxxxxxxxxxxxx
    bucket-name: my-test-bucket
方式 2:application.properties
# 前缀 + 属性名,用 "." 分隔
custom.oss.endpoint=https://oss-cn-beijing.aliyuncs.com
custom.oss.access-key=LTAI4Gxxxxxxx
custom.oss.secret-key=8Zxxxxxxxxxxxxxx
custom.oss.bucket-name=my-test-bucket

步骤 3:注册配置属性类(3 种方式)

​@ConfigurationProperties​​ 本身不会将类注册为 Spring Bean,需配合以下方式之一让 Spring 扫描到该类:

方式 1:直接在实体类上加 ​​@Component​​(简单场景)

如步骤 1 中的代码,直接在 ​​OssProperties​​ 上添加 ​​@Component​​(或 ​​@Configuration​​),Spring 会自动扫描并注入属性(需确保该类在 ​​@SpringBootApplication​​ 的扫描范围内,即包路径一致或子路径)。

方式 2:在配置类中用 ​​@EnableConfigurationProperties​​ 激活(推荐,解耦)

如果不想在实体类上加 ​​@Component​​(例如实体类在第三方包中,无法修改),可在任意 ​​@Configuration​​ 类(如启动类)上添加 ​​@EnableConfigurationProperties​​,指定要激活的配置属性类:

import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
// 激活 OssProperties,Spring 会自动将其注册为 Bean
@EnableConfigurationProperties(OssProperties.class)
public class MyApplication {
    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}
方式 3:在配置类中用 ​​@Bean​​ 手动注册(灵活控制)

通过 ​​@Bean​​ 方法手动创建配置属性类的实例,适用于需要自定义初始化逻辑的场景:

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class OssConfig {
    // 手动注册 OssProperties 为 Bean,并绑定配置
    @Bean
    @ConfigurationProperties(prefix = "custom.oss")
    public OssProperties ossProperties() {
        // 可在这里添加自定义初始化逻辑
        return new OssProperties();
    }
}

步骤 4:使用配置属性(注入 Bean 即可)

在业务类(如 Service、Controller)中,通过 ​​@Autowired​​ 注入配置属性类,直接使用绑定后的属性:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OssService {
    // 注入配置属性类(Spring 已自动绑定配置文件中的值)
    @Autowired
    private OssProperties ossProperties;

    public void uploadFile() {
        // 直接使用配置属性
        String endpoint = ossProperties.getEndpoint();
        String accessKey = ossProperties.getAccessKey();
        System.out.println("OSS 上传地址:" + endpoint);
        System.out.println("AccessKey:" + accessKey);
        // 后续业务逻辑...
    }
}

二、进阶场景(实用功能)

1. 层级化配置(嵌套属性)

如果配置存在多层嵌套(如 ​​custom.oss.cdn.domain​​),可通过嵌套内部类独立类实现绑定。

示例:嵌套配置
(1)配置文件(application.yml)
custom:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    access-key: LTAI4Gxxxxxxx
    secret-key: 8Zxxxxxxxxxxxxxx
    bucket-name: my-test-bucket
    # 嵌套属性:CDN 相关配置
    cdn:
      domain: https://cdn.my-bucket.com
      expire: 3600  # 链接有效期(秒)
(2)配置属性类(嵌套内部类)
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

@ConfigurationProperties(prefix = "custom.oss")
@Component
public class OssProperties {
    private String endpoint;
    private String accessKey;
    private String secretKey;
    private String bucketName;
    // 嵌套内部类:对应 custom.oss.cdn
    private Cdn cdn;

    // getter/setter(包括 Cdn 的 getter/setter)
    public String getEndpoint() { return endpoint; }
    public void setEndpoint(String endpoint) { this.endpoint = endpoint; }
    // ... 其他属性的 getter/setter

    public Cdn getCdn() { return cdn; }
    public void setCdn(Cdn cdn) { this.cdn = cdn; }

    // 嵌套内部类(必须是 static,否则无法绑定)
    public static class Cdn {
        private String domain;
        private Integer expire;

        // getter/setter
        public String getDomain() { return domain; }
        public void setDomain(String domain) { this.domain = domain; }
        public Integer getExpire() { return expire; }
        public void setExpire(Integer expire) { this.expire = expire; }
    }
}
(3)使用嵌套属性
@Service
public class OssService {
    @Autowired
    private OssProperties ossProperties;

    public void getCdnInfo() {
        // 访问嵌套属性:custom.oss.cdn.domain
        String cdnDomain = ossProperties.getCdn().getDomain();
        Integer cdnExpire = ossProperties.getCdn().getExpire();
        System.out.println("CDN 域名:" + cdnDomain + ",有效期:" + cdnExpire + "秒");
    }
}

2. 松散绑定(属性名不严格匹配)

​@ConfigurationProperties​​ 支持松散的属性名绑定,即配置文件中的属性名格式与 Java 实体类的属性名格式可以不一致,Spring 会自动匹配。

支持的绑定规则:

Java 实体类属性名(驼峰式)配置文件中允许的格式
​accessKey​​access-key​​​(中划线,推荐.yml)、​​access_key​​​(下划线)、​​accessKey​​​(驼峰)、​​ACCESS_KEY​​(全大写)
​bucketName​​bucket-name​​​、​​bucket_name​​​、​​bucketName​​​、​​BUCKET_NAME​
示例:

Java 类属性:​​private String accessKey;​​ 配置文件中可写:

custom:
  oss:
    access-key: LTAI4Gxxxxxxx  # 推荐(yml 风格)
    # 或 access_key: LTAI4Gxxxxxxx
    # 或 accessKey: LTAI4Gxxxxxxx
    # 或 ACCESS_KEY: LTAI4Gxxxxxxx

3. 配置属性校验(避免非法值)

通过 ​​JSR-380​​ 注解(如 ​​@NotNull​​、​​@Min​​、​​@Pattern​​)对配置属性进行校验,确保配置值合法。需先添加校验依赖,再在实体类上添加校验注解。

步骤 1:添加校验依赖

Maven(pom.xml):

<!-- 配置属性校验依赖(Spring Boot 2.x+ 已包含,若缺失则添加) -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Gradle:

implementation 'org.springframework.boot:spring-boot-starter-validation'
步骤 2:在实体类上添加校验注解
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Positive;

// 1. 添加 @Validated 开启校验(必须)
@Validated
@ConfigurationProperties(prefix = "custom.oss")
@Component
public class OssProperties {
    // 非空校验:配置文件中必须存在 custom.oss.endpoint
    @NotBlank(message = "OSS endpoint 不能为空")
    private String endpoint;

    @NotBlank(message = "accessKey 不能为空")
    private String accessKey;

    @NotBlank(message = "secretKey 不能为空")
    private String secretKey;

    @NotBlank(message = "bucketName 不能为空")
    private String bucketName;

    // 嵌套属性校验(内部类也需加 @Valid)
    @Valid
    private Cdn cdn;

    // getter/setter...

    public static class Cdn {
        @NotBlank(message = "CDN domain 不能为空")
        private String domain;

        // 正数校验:expire 必须大于 0
        @NotNull(message = "CDN expire 不能为空")
        @Positive(message = "CDN expire 必须为正数")
        private Integer expire;

        // getter/setter...
    }
}
效果:

若配置文件中缺失 ​​custom.oss.endpoint​​ 或 ​​cdn.expire​​ 为负数,应用启动时会直接抛出 ​​BindValidationException​​,明确提示错误原因,避免运行时异常。

4. 配置默认值(避免配置缺失)

可在 Java 实体类的属性中直接设置默认值,当配置文件中未指定该属性时,会使用默认值:

@ConfigurationProperties(prefix = "custom.oss")
@Component
public class OssProperties {
    // 默认值:若配置文件中未写 custom.oss.endpoint,则使用该值
    private String endpoint = "https://oss-cn-hangzhou.aliyuncs.com";
    private String accessKey;
    private String secretKey;
    // 嵌套属性默认值
    private Cdn cdn = new Cdn(); // 初始化嵌套类

    // getter/setter...

    public static class Cdn {
        private String domain = "https://default-cdn.com";
        private Integer expire = 7200; // 默认有效期 2 小时

        // getter/setter...
    }
}

三、常见问题与注意事项

1. 配置属性注入失败?(排查步骤)

  • 检查配置文件中的 ​​prefix​​ 与属性名是否匹配(如 ​​custom.oss​​ 对应 ​​custom.oss.endpoint​​);
  • 确保配置属性类已注册为 Spring Bean(加 ​​@Component​​ 或通过 ​​@EnableConfigurationProperties​​ 激活);
  • 确保属性提供了 ​​getter/setter​​ 方法(Spring 通过 setter 注入值,无 setter 则无法绑定);
  • 检查配置文件是否在正确路径下(默认是 ​​src/main/resources/application.yml​​/​​application.properties​​);
  • 若使用 ​​@EnableConfigurationProperties​​,确保该注解加在 ​​@Configuration​​ 类(如启动类)上。

2. 区分 ​​@ConfigurationProperties​​ 与 ​​@Value​

特性​@ConfigurationProperties​​@Value​
用途批量绑定多属性、层级属性单个属性注入
松散绑定支持(如 ​​access-key​​​ 绑定 ​​accessKey​​)不支持(需严格匹配属性名)
类型转换自动转换(如 String → Integer)需手动指定转换器(如 ​​@Value("${xxx:#{T(Integer).valueOf('10')}}")​​)
校验支持支持(配合 ​​@Validated​​)不支持(需手动校验)
适用场景复杂配置(数据库、第三方 API)简单单个属性(如端口、环境变量)

3. 读取自定义配置文件(非 application.yml)

默认情况下,​​@ConfigurationProperties​​ 读取 ​​application.yml​​/​​application.properties​​。若需读取自定义文件(如 ​​src/main/resources/config/oss-config.yml​​),可配合 ​​@PropertySource​​ 注解(注意:​​@PropertySource​​ 默认不支持 YAML 文件,需额外配置):

步骤 1:添加 YAML 解析器(支持 ​​@PropertySource​​ 读取 YAML)
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.support.DefaultPropertySourceFactory;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import java.io.IOException;
import java.util.List;
import org.springframework.core.env.PropertySource;

// 自定义 PropertySourceFactory,支持 YAML 文件
public class YamlPropertySourceFactory implements PropertySourceFactory {
    @Override
    public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException {
        List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource());
        return sources.get(0);
    }
}
步骤 2:在配置属性类上指定自定义文件
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@ConfigurationProperties(prefix = "custom.oss")
@Component
// 指定自定义 YAML 文件,使用上面的 YamlPropertySourceFactory
@PropertySource(value = "classpath:config/oss-config.yml", factory = YamlPropertySourceFactory.class)
public class OssProperties {
    // 属性 + getter/setter...
}

四、总结

​@ConfigurationProperties​​ 是 Spring Boot 中管理配置的核心注解,核心优势是批量绑定、层级支持、松散绑定、校验能力,适合处理复杂配置场景。

使用流程可简化为:

  1. 定义实体类 + ​​@ConfigurationProperties(prefix = "xxx")​​;
  2. 注册为 Spring Bean(​​@Component​​ 或 ​​@EnableConfigurationProperties​​);
  3. 配置文件中添加对应属性;
  4. 业务类中注入实体类使用。

掌握其进阶功能(校验、默认值、嵌套配置)可大幅提升配置管理的规范性和稳定性,避免运行时配置相关的 Bug。