介绍
@ConfigurationProperties 是 Spring 框架中的一个注解,用于将配置文件中的属性映射到 Java 对象的字段上。它的主要用途是简化配置文件与 Java 对象之间的映射过程,使得配置更加方便、可读,并提供类型安全的属性访问。
用途和特性
-
属性映射: 将配置文件中的属性映射到 Java 对象的字段上。这样,可以通过在 Java 类中定义字段来组织和访问应用程序的配置。
-
类型安全: 通过在 Java 类型上使用注解,可以实现类型安全的属性访问。如果配置文件中的属性与 Java 类型不匹配,Spring 在启动时会报错,提前发现配置错误。
-
嵌套属性: 支持将配置文件中的属性嵌套到 Java 对象的嵌套字段中,使得可以更结构化地组织配置信息。
-
多环境支持: 可以通过在注解中指定 prefix 属性,将不同环境下的配置信息分组,从而实现多环境配置。
-
默认值: 可以为字段设置默认值,如果配置文件中没有相应的属性,将使用默认值。
-
动态刷新: 在 Spring Boot 中,@ConfigurationProperties 还支持动态刷新,当配置发生变化时,可以通过 @RefreshScope 注解实现动态刷新,而不需要重启应用程序。
-
属性验证: 可以使用 @Validated 注解结合 JSR 303 标准的验证注解,对配置属性进行验证。
示例如下:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
private String appName;
private int maxConnections;
// other properties...
// getters and setters...
}
在上面的例子中,@ConfigurationProperties 注解指定了 prefix 属性为 “myapp”,表示配置文件中的属性应该以 “myapp” 为前缀。例如,配置文件中的属性可以是 myapp.appName 和 myapp.maxConnections。这些属性将被映射到 MyAppProperties 类的相应字段上。
与@Value的区别
@ConfigurationProperties 和 @Value 是 Spring 中用于获取配置信息的两种不同方式
- 类型安全:
@ConfigurationProperties 提供了类型安全的配置绑定。你可以创建一个 Java 类,将配置属性映射到该类的字段上,Spring 会自动将配置文件中的值绑定到相应的字段,而且会进行类型转换。如果类型不匹配,Spring 会在启动时报错。
@Value 是基于 SpEL(Spring Expression Language)的,它是一个字符串表达式,不提供类型安全性。你需要手动进行类型转换,并且如果类型不匹配,可能会导致运行时错误。
- 多属性绑定:
@ConfigurationProperties 支持将多个属性绑定到一个类中,使得配置更加结构化,适用于组织复杂的配置信息。
@Value 一般用于单一属性的注入,较难组织复杂的配置信息。
- 适用场景:
@ConfigurationProperties 适用于大量配置属性、多个相关配置属性的情况,尤其是复杂的配置信息。
@Value 适用于简单的属性注入,对于少量的配置项。
最大的区别在于第一点类型安全上
:
使用 @ConfigurationProperties 时,可以将配置文件中的属性直接映射到一个 Java 类的字段上。Spring 在启动时会尝试将配置文件中的值转换为字段声明的类型。如果类型不匹配,Spring 会在启动时检测到并报告错误。这种类型检查是在应用程序启动时进行的,有助于提前发现配置错误,而不是在运行时发生意外行为。
其次就是可以通过java类管理配置属性,对于配置属性较多情况下可以使其更加统一
@value的优点体现在对于两个关系不大的配置上,比如有myapp.aaa.ccc.bbb=1和myapp.qqq=2这样的两个配置
如果使用@ConfigurationProperties注解,需要嵌套方式去获取内容,如下:
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
private final AAA aaa = new AAA();
private int qqq;
public static class AAA {
private final CCC ccc = new CCC();
public static class CCC {
private int bbb;
public int getBbb() {
return bbb;
}
public void setBbb(int bbb) {
this.bbb = bbb;
}
}
public CCC getCcc() {
return ccc;
}
}
public AAA getAaa() {
return aaa;
}
public int getQqq() {
return qqq;
}
public void setQqq(int qqq) {
this.qqq = qqq;
}
}
结论
结合@ConfigurationProperties的优点,我们在约定配置文件时,相同的业务配置尽量有统一的前缀和减少嵌套(通过下划线或者横杠映射类的驼峰命名),不同的业务配置有不同的prefix。这样便于使用一个配置类管理。示例如下:
补充
补充一些其他类似的spring注解
- @ConditionalOnproperity
@ConditionalOnProperty 是 Spring Boot 中的一个条件注解,用于根据配置属性的值来决定是否要启用某个配置类、Bean 或组件。这个注解在以下场景中特别有用:
特定配置开关: 你可以使用 @ConditionalOnProperty 来根据配置文件中的某个属性值来决定是否启用某个配置。例如,只有在配置文件中设置了特定的属性时,某个Bean 或配置类才会生效。
@Configuration
@ConditionalOnProperty(name = "myapp.feature.enabled", havingValue = "true")
public class MyFeatureConfiguration {
// 配置类的内容...
}
myapp.feature.enabled=true,这样配置类 MyFeatureConfiguration 就会在属性 myapp.feature.enabled 的值为 true 时生效。
- @ConditionalOnMissingBean
@ConditionalOnMissingBean 是 Spring Boot 中的一个条件注解,用于在特定的 Bean 还不存在时启用某个配置类、Bean 或组件。这个注解在以下场景中特别有用:
默认实现: 当你有一个接口或抽象类有多个实现时,可以使用 @ConditionalOnMissingBean 注解来提供一个默认的实现。如果容器中已经有了某个实现的 Bean,那么就不会再创建这个默认实现的 Bean。
@Service
public class DefaultMyService implements MyService {
// 默认实现的内容...
}
@Service
@ConditionalOnMissingBean(MyService.class)
public class CustomMyService implements MyService {
// 自定义实现的内容...
}
在这个例子中,如果容器中已经有了类型为 MyService 的 Bean(例如 DefaultMyService),那么 CustomMyService 就不会被创建。如果没有,就会创建 CustomMyService。
插件化扩展: 当你提供一种插件机制,允许开发者在应用程序中注册自定义实现时,可以使用 @ConditionalOnMissingBean。这样,如果用户自己定义了实现,就使用用户的实现;否则,使用默认实现。
@Configuration
public class MyConfig {
@Bean
@ConditionalOnMissingBean
public MyPlugin myPlugin() {
return new DefaultMyPlugin();
}
}
在这个例子中,如果容器中已经有了 MyPlugin 类型的 Bean,那么 myPlugin 方法就不会创建新的 Bean;否则,它会创建一个默认的 DefaultMyPlugin Bean。