属性绑定
Spring Boot 提供两套属性注入机制:@Value(单值注入)和 @ConfigurationProperties(类型安全的批量绑定)。
@Value vs @ConfigurationProperties
| 对比 | @Value | @ConfigurationProperties |
|---|---|---|
| 注入粒度 | 单个属性 | 一组相关属性 |
| 类型安全 | 有限 | 完整(嵌套对象、集合、Duration 等) |
| 校验支持 | 无 | @Validated + JSR-303 |
| IDE 补全 | 无 | 有(需配置元数据处理器) |
| SpEL 支持 | 支持 | 不支持 |
| 默认值 | ${key:default} | 字段初始值 |
| 适用场景 | 少量、临时、需要 SpEL | 模块化配置类,推荐 |
@Value
@Service
public class AppService {
@Value("${server.port}")
private int port;
// 冒号后为默认值(属性不存在时使用)
@Value("${app.name:未命名应用}")
private String appName;
// 注入列表(逗号分隔)
@Value("${app.cors.origins:http://localhost:3000}")
private List<String> corsOrigins;
// SpEL 表达式:读取系统属性
@Value("#{systemProperties['user.home']}")
private String userHome;
// SpEL:计算表达式
@Value("#{${app.timeout} * 1000}")
private long timeoutMs;
// SpEL:引用其他 Bean 的属性
@Value("#{dataSource.maxPoolSize}")
private int maxConnections;
}
@Value在 Bean 构造期间注入,构造函数参数无法使用@Value,应改用@ConfigurationProperties+ 构造函数绑定。
@ConfigurationProperties
基础用法
@ConfigurationProperties(prefix = "app.mail")
@Data // Lombok,生成 getter/setter(绑定要求 setter 存在)
public class MailProperties {
/** 邮件服务器地址 */
private String host = "smtp.example.com";
/** 端口,默认 25 */
private int port = 25;
/** 发件人地址 */
private String from;
/** 是否启用 SSL */
private boolean ssl = false;
/** 连接超时 */
private Duration connectionTimeout = Duration.ofSeconds(10);
}app:
mail:
host: smtp.gmail.com
port: 587
from: noreply@example.com
ssl: true
connection-timeout: 30s注册方式(二选一)
// 方式一:启动类或配置类上扫描(推荐,批量注册)
@SpringBootApplication
@ConfigurationPropertiesScan("com.example.config")
public class Application { }
// 方式二:显式注册单个类
@Configuration
@EnableConfigurationProperties(MailProperties.class)
public class MailConfig { }
// 方式三:类上加 @Component(不推荐,混淆了配置与 Bean 的职责)
@Component
@ConfigurationProperties(prefix = "app.mail")
public class MailProperties { }Relaxed Binding(宽松绑定)
Spring Boot 自动将不同格式的 key 统一映射到驼峰命名的 Java 字段:
配置 key Java 字段
─────────────────────────────────────────
app.max-pool-size → maxPoolSize (kebab-case,推荐写法)
APP_MAX_POOL_SIZE → maxPoolSize (环境变量 UPPER_SNAKE_CASE)
app.maxPoolSize → maxPoolSize (camelCase)
app.max_pool_size → maxPoolSize (snake_case)
环境变量优先级高于配置文件,在 Docker / K8s 中常用环境变量覆盖配置文件中的值。详见 配置管理。
嵌套对象
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {
private String name;
private Server server = new Server();
private Database database = new Database();
@Data
public static class Server {
private String host = "localhost";
private int port = 8080;
private Ssl ssl = new Ssl();
@Data
public static class Ssl {
private boolean enabled = false;
private String keyStore;
private String keyStorePassword;
}
}
@Data
public static class Database {
private String url;
private String username;
private int maxPoolSize = 20;
private Duration queryTimeout = Duration.ofSeconds(30);
}
}app:
name: my-service
server:
host: api.example.com
port: 443
ssl:
enabled: true
key-store: classpath:keystore.p12
key-store-password: ${SSL_PASSWORD}
database:
url: jdbc:mysql://db:3306/mydb
username: app
max-pool-size: 50
query-timeout: 10s集合与 Map 绑定
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {
// List<String>
private List<String> allowedOrigins = new ArrayList<>();
// List<对象>
private List<DataSource> dataSources = new ArrayList<>();
// Map<String, String>
private Map<String, String> headers = new HashMap<>();
// Map<String, 对象>
private Map<String, RouteConfig> routes = new HashMap<>();
@Data
public static class DataSource {
private String url;
private String username;
}
@Data
public static class RouteConfig {
private String target;
private int timeout;
}
}app:
allowed-origins:
- http://localhost:3000
- https://app.example.com
data-sources:
- url: jdbc:mysql://primary:3306/db
username: root
- url: jdbc:mysql://replica:3306/db
username: reader
headers:
X-App-Name: my-service
X-Version: "1.0"
routes:
users:
target: http://user-service
timeout: 3000
orders:
target: http://order-service
timeout: 5000特殊类型绑定
Spring Boot 自动处理以下类型,无需自定义 Converter:
@ConfigurationProperties(prefix = "app")
@Data
public class AppProperties {
// Duration:30s / 5m / 1h / 1d
private Duration connectTimeout = Duration.ofSeconds(30);
private Duration sessionTimeout = Duration.ofMinutes(30);
// DataSize:100MB / 1GB / 512KB
private DataSize maxUploadSize = DataSize.ofMegabytes(10);
private DataSize bufferSize = DataSize.ofKilobytes(8);
// Charset
private Charset encoding = StandardCharsets.UTF_8;
// InetAddress
private InetAddress bindAddress;
// Resource
private Resource templateFile;
// Enum(大小写不敏感)
private LogLevel logLevel = LogLevel.INFO;
}app:
connect-timeout: 30s
session-timeout: 30m
max-upload-size: 50MB
buffer-size: 16KB
log-level: warn # 等价于 WARN构造函数绑定(不可变配置)
Spring Boot 2.2+ 支持通过构造函数绑定,配置类不需要 setter,天然不可变:
@ConfigurationProperties(prefix = "app.jwt")
// Spring Boot 3.x 直接在类上加,无需 @ConstructorBinding
public record JwtProperties(
String secret,
Duration accessTokenExpiry,
Duration refreshTokenExpiry
) {
// record 自带 compact constructor,可在此做校验
public JwtProperties {
Objects.requireNonNull(secret, "JWT secret 不能为空");
if (secret.length() < 32) {
throw new IllegalArgumentException("JWT secret 长度不能小于 32 位");
}
}
}app:
jwt:
secret: ${JWT_SECRET}
access-token-expiry: 2h
refresh-token-expiry: 7d配置校验(@Validated)
@ConfigurationProperties(prefix = "app.mail")
@Validated // 启动时若校验失败,应用拒绝启动
@Data
public class MailProperties {
@NotBlank(message = "邮件服务器地址不能为空")
private String host;
@Min(1) @Max(65535)
private int port = 25;
@Email(message = "发件人地址格式不正确")
@NotBlank
private String from;
@NotNull
private Duration timeout = Duration.ofSeconds(10);
// 嵌套对象也可以校验
@Valid
@NotNull
private Ssl ssl = new Ssl();
@Data
public static class Ssl {
@AssertTrue(message = "开启 SSL 时必须配置证书路径")
private boolean certConfigured;
}
}参数校验规则详见 参数校验。
IDE 自动补全支持
添加注解处理器后,IDE 在 application.yml 中编辑配置时自动提示字段名、类型和 Javadoc 说明:
// build.gradle
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'编译后生成 META-INF/spring-configuration-metadata.json,也可手动补充描述:
// META-INF/additional-spring-configuration-metadata.json
{
"properties": [
{
"name": "app.mail.host",
"type": "java.lang.String",
"description": "SMTP 服务器地址,如 smtp.gmail.com"
},
{
"name": "app.mail.port",
"type": "java.lang.Integer",
"description": "SMTP 端口,TLS 通常为 587,SSL 为 465",
"defaultValue": 25
}
]
}