@ConfigurationProperties
简介
说明
对于application.yml里边的配置,我们可以通过@Value来获得,比如:@Value("${user.name}")。但是,如果属性很多,写很多个@Value就会很繁琐。
解决方案就是:使用@ConfigurationProperties,将一组属性通过一个类来接收。
注意
- 保存属性的类必须加getter和setter。
- 名字不能有这些:大写字母、特殊字符(比如:-,_)
宽松绑定
以下方式写法相当于同一种写法。比如:yml用helloname,代码可以用helloName获取其值。
helloname
helloName
HELLONAME
hello-name
hello_name
HELLO-NAME
@ConfigurationProperties与@Value
项 | @ConfigurationProperties | @Value |
类型 | Map、内部类、对象等。 | 不支持内部类、对象。 |
spEl表达式 | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
功能 | 一个列属性批量注入 | 单属性注入 |
激活
法1:@ConfigurationProperties+@Component
(prefix = "hello")
public class HelloProperties {
private String name;
private List<String> emails;
private Map<String, Integer> price;
//getter and setter
}
法2:@ConfigurationProperties+@Bean
此时HelloProperties不需要加任何注解。
public class Config {
(prefix = "hello")
public HelloProperties helloProperties(){
return new HelloProperties();
}
}
法3:@ConfigurationProperties+@Configuration+@EnableConfigurationProperties
在有@Configuration注解类中加上注解@EnableConfigurationProperties来声明。比如@Configuration、启动类:
(HelloProperties.class)
public class ConfigurationPropertiesDemoApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigurationPropertiesDemoApplication.class, args);
}
}
原理分析
springboot(四)——@EnableConfigurationProperties是如何起作用的你知道吗 -
实例
application.yml
hello:
relaxed:
enabled: true
helloname1: helloname1
helloName2: helloName2
HELLONAME3: HELLONAME3
hello-name4: hello-name4
hello_name5: hello_name5
HELLO-NAME6: HELLO-NAME6
hiname1: hiname1
hiName2: hiName2
HINAME3: HINAME3
hi-name4: hi-name4
hi_name5: hi_name5
HI-NAME6: HI-NAME6
child:
childName1: childName
id: 1000
配置类
package com.example.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class ConfigPropConf {
(prefix = "hello.relaxed")
public HelloProperties httpsProperties() {
return new HelloProperties();
}
}
顶层属性类
package com.example.config;
public class HelloProperties {
private Boolean enabled;
private String helloName1;
private String helloName2;
private String helloName3;
private String helloName4;
private String helloName5;
private String helloName6;
private String hiname1;
private String hiname2;
private String hiname3;
private String hiname4;
private String hiname5;
private String hiname6;
private ChildProperties child;
public Boolean getEnabled() {
return enabled;
}
public void setEnabled(Boolean enabled) {
this.enabled = enabled;
}
public String getHelloName1() {
return helloName1;
}
public void setHelloName1(String helloName1) {
this.helloName1 = helloName1;
}
public String getHelloName2() {
return helloName2;
}
public void setHelloName2(String helloName2) {
this.helloName2 = helloName2;
}
public String getHelloName3() {
return helloName3;
}
public void setHelloName3(String helloName3) {
this.helloName3 = helloName3;
}
public String getHelloName4() {
return helloName4;
}
public void setHelloName4(String helloName4) {
this.helloName4 = helloName4;
}
public String getHelloName5() {
return helloName5;
}
public void setHelloName5(String helloName5) {
this.helloName5 = helloName5;
}
public String getHelloName6() {
return helloName6;
}
public void setHelloName6(String helloName6) {
this.helloName6 = helloName6;
}
public String getHiname1() {
return hiname1;
}
public void setHiname1(String hiname1) {
this.hiname1 = hiname1;
}
public String getHiname2() {
return hiname2;
}
public void setHiname2(String hiname2) {
this.hiname2 = hiname2;
}
public String getHiname3() {
return hiname3;
}
public void setHiname3(String hiname3) {
this.hiname3 = hiname3;
}
public String getHiname4() {
return hiname4;
}
public void setHiname4(String hiname4) {
this.hiname4 = hiname4;
}
public String getHiname5() {
return hiname5;
}
public void setHiname5(String hiname5) {
this.hiname5 = hiname5;
}
public String getHiname6() {
return hiname6;
}
public void setHiname6(String hiname6) {
this.hiname6 = hiname6;
}
public ChildProperties getChild() {
return child;
}
public void setChild(ChildProperties child) {
this.child = child;
}
}
子层属性类
package com.example.config;
public class ChildProperties {
private String child_Name1;
private Long id;
public String getChild_Name1() {
return child_Name1;
}
public void setChild_Name1(String child_Name1) {
this.child_Name1 = child_Name1;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
控制器
package com.example.controller;
import com.example.config.HelloProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.time.LocalDateTime;
("/hello")
public class HelloController {
private HelloProperties helloProperties;
("/prop")
public HelloProperties prop() {
return helloProperties;
}
}
测试
访问:http://localhost:8080/hello/prop
条件注入
简介
源码中的使用
在Spring Boot的源码中,比如涉及到Http编码的自动配置、数据源类型的自动配置等大量的使用到了@ConditionalOnProperty的注解。
HttpEncodingAutoConfiguration类中部分源代码:
proxyBeanMethods = false)
(HttpProperties.class)
(type = ConditionalOnWebApplication.Type.SERVLET)
(CharacterEncodingFilter.class)
(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
// 省略内部代码
}
(
DataSourceConfiguration类中部分代码:
proxyBeanMethods = false)
(org.apache.tomcat.jdbc.pool.DataSource.class)
(DataSource.class)
(name = "spring.datasource.type", havingValue = "org.apache.tomcat.jdbc.pool.DataSource",
matchIfMissing = true)
static class Tomcat {
// 省略内部代码
}
(
已有的实现
其他网址
Spring Boot 2 实战:使用 @Condition 注解来根据条件注入 Bean
简介
注解 | 说明 | 示例 |
@ConditionalOnProperty | 要求配置属性匹配条件 | @ConditionalOnProperty( prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) |
@ConditionalOnBean | 容器中存在对应实例时,返回true。 当给定的类型、类名、注解、昵称在beanFactory中存在时返回true。 若不指定name,则为本bean的名字。 | @ConditionalOnBean @ConditionalOnBean(name="abc") |
@ConditionalOnMissingBean | 容器中不存在对应实例时,返回true。 当给定的类型、类名、注解、昵称在beanFactory中不存在时返回true。各类型间是or的关系。 若不指定name,则为本bean的名字。 | |
@ConditionalOnClass | 当给定的类在类路径上存在时返回true,各类型间是and的关系 | @ConditionalOnClass(Abc.class) |
@ConditionalOnMissingClass | 当给定的类在类路径上不存在时返回true,各类型间是and的关系 | |
@ConditionalOnSingleCandidate | 当给定类型的bean存在并且指定为Primary的给定类型存在时,返回true | |
@ConditionalOnCloudPlatform | 当所配置的CloudPlatform为激活时返回true | |
@ConditionalOnExpression | spel表达式执行为true | 详见下方。 |
@ConditionalOnJava | 运行时的java版本号是否包含给定的版本号.如果包含,返回匹配,否则,返回不匹配 | |
@ConditionalOnJndi | 给定的jndi的Location 必须存在一个.否则,返回不匹配 | |
@ConditionalOnNotWebApplication | web环境不存在时 | |
@ConditionalOnWebApplication | web环境存在时 | |
@ConditionalOnResource | 要求制定的资源存在 |
@ConditionalOnProperty
RetentionPolicy.RUNTIME)
({ElementType.TYPE, ElementType.METHOD})
({OnPropertyCondition.class})
public @interface ConditionalOnProperty {
String[] value() default {}; //数组,获取对应property名称的值,与name不可同时使用
String prefix() default ""; //property名称的前缀,可有可无
String[] name() default {}; //数组,property完整名称或部分名称(可与prefix组合使用,组成完整的property名称),与value不可同时使用
String havingValue() default ""; //可与name组合使用,比较获取到的属性值与havingValue给定的值是否相同,相同才加载配置
boolean matchIfMissing() default false; //缺少该property时是否可以加载。如果为true,没有该property也会正常加载;反之报错
}
(
单个值
@ConditionalOnProperty("config1.enable", havingValue="true")
多个值
@ConditionalOnProperty(name={"config1.enable","config.all"}, havingValue="true")
@ConditionalOnExpression
或/与
config1.enabled为true或者config2.enabled 为true
@ConditionalOnExpression("${config1.enabled:false} || ${config2.enabled:false}")
与时类似。换成&&即可。
计算
@ConditionalOnExpression("${mq.cumsumer.enabled}==1 && ${rabbitmq.comsumer.enabled:true}")
取反
config1.enabled为true而且config2.enabled 为false
@ConditionalOnExpression("${config1.enabled:false} && !${config2.enabled:false}")
equals
@ConditionalOnExpression("'${mq.comsumer}'.equals('rabbitmq')")
分级
例2:若局部有配置,按局部配置。否则,按全局配置。若全局、局部都没配置,则不导入。
本处:config2.enabled为局部,config.all.enabled为全局
@ConditionalOnExpression(value = "${config2.enabled:${config.all.enabled:false}}")
已有的实现的实例
@Component、@Configuration+@Bean都可以与条件注入的注解结合。
@Component+条件注解
Bean
package com.example.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;
(name = "custom.myComponent.enabled", havingValue = "true")
public class MyComponent {
public MyComponent() {
System.out.println("[MyComponent#MyComponent]");
}
}
application.yml
custom:
myComponent:
enabled: true
运行结果:
[MyComponent#MyComponent]
若将application.yml的custom.myComponent.enabled去掉,或者设置为非true值,则不会输出上边的运行结果。
@Configuration+@Bean+条件注解
Bean
package com.example.config;
public class MyComponent {
public MyComponent() {
System.out.println("[MyComponent#MyComponent]");
}
}
配置类
package com.example.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
public class MyConfig {
(name = "custom.myComponent.enabled", havingValue = "true")
public MyComponent getMyComponent() {
return new MyComponent();
}
}
application.yml
custom:
myComponent:
enabled: true
运行结果:
[MyComponent#MyComponent]
若将application.yml的custom.myComponent.enabled去掉,或者设置为非true值,则不会输出上边的运行结果。
@Configuration+条件注解+@Bean
Bean
package com.example.config;
public class MyComponent {
public MyComponent() {
System.out.println("[MyComponent#MyComponent]");
}
}
配置类
package com.example.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
(name = "custom.myComponent.enabled", havingValue = "true")
public class MyConfig {
public MyComponent getMyComponent() {
return new MyComponent();
}
}
application.yml
custom:
myComponent:
enabled: true
运行结果:
[MyComponent#MyComponent]
若将application.yml的custom.myComponent.enabled去掉,或者设置为非true值,则不会输出上边的运行结果。
自定义Condition
自定义的condition的matches方法返回值为true时,才会创建bean。
条件类
//判断当前系统是否是Mac
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata;
public class MyCondition implements Condition {
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("os.name").contains("Mac");
}
}
public class Config {
(MyCondition.class)
public String condition() {
System.err.println("This is mac");
return "";
}
}
其他网址
@ConfigurationProperties 注解使用姿势,这一篇就够了
【Springboot】注解@ConfigurationProperties让配置整齐而简单 - 知乎