0
点赞
收藏
分享

微信扫一扫

SpringBoot--获得配置



@ConfigurationProperties

简介

说明

        对于application.yml里边的配置,我们可以通过@Value来获得,比如:@Value("${user.name}")。但是,如果属性很多,写很多个@Value就会很繁琐。

        解决方案就是:使用@ConfigurationProperties,将一组属性通过一个类来接收。

注意

  1. 保存属性的类必须加getter和setter。
  2. 名字不能有这些:大写字母、特殊字符(比如:-,_)

宽松绑定

以下方式写法相当于同一种写法。比如:yml用helloname,代码可以用helloName获取其值。

helloname

helloName

HELLONAME

hello-name

hello_name

HELLO-NAME

@ConfigurationProperties与@Value

@ConfigurationProperties

@Value

类型

Map、内部类、对象等。

不支持内部类、对象。

spEl表达式

不支持

支持

JSR303数据校验

支持

不支持

功能

一个列属性批量注入

单属性注入

激活

法1:@ConfigurationProperties+@Component

@Component
@ConfigurationProperties(prefix = "hello")
public class HelloProperties {
private String name;
private List<String> emails;
private Map<String, Integer> price;
//getter and setter
}

法2:@ConfigurationProperties+@Bean

此时HelloProperties不需要加任何注解。 

@Configuration
public class Config {
@Bean
@ConfigurationProperties(prefix = "hello")
public HelloProperties helloProperties(){
return new HelloProperties();
}
}

法3:@ConfigurationProperties+@Configuration+@EnableConfigurationProperties

在有@Configuration注解类中加上注解@EnableConfigurationProperties来声明。比如@Configuration、启动类:

@SpringBootApplication
@EnableConfigurationProperties(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;

@Configuration
public class ConfigPropConf {
@Bean
@ConfigurationProperties(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;

@RestController
@RequestMapping("/hello")
public class HelloController {
@Autowired
private HelloProperties helloProperties;

@GetMapping("/prop")
public HelloProperties prop() {
return helloProperties;
}
}

测试

访问:​​http://localhost:8080/hello/prop​​

SpringBoot--获得配置_java

条件注入

简介

源码中的使用

在Spring Boot的源码中,比如涉及到Http编码的自动配置、数据源类型的自动配置等大量的使用到了@ConditionalOnProperty的注解。

HttpEncodingAutoConfiguration类中部分源代码:

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(HttpProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
// 省略内部代码
}

DataSourceConfiguration类中部分代码:

@Configuration(proxyBeanMethods = false)
@ConditionalOnClass(org.apache.tomcat.jdbc.pool.DataSource.class)
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(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

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional({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;

@Component
@ConditionalOnProperty(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;

@Configuration
public class MyConfig {
@Bean
@ConditionalOnProperty(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;

@Configuration
@ConditionalOnProperty(name = "custom.myComponent.enabled", havingValue = "true")
public class MyConfig {
@Bean
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 {
@Override
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) {
return conditionContext.getEnvironment().getProperty("os.name").contains("Mac");
}
}
@Configuration
public class Config {
@Conditional(MyCondition.class)
@Bean
public String condition() {
System.err.println("This is mac");
return "";
}
}

其他网址

​​@ConfigurationProperties 注解使用姿势,这一篇就够了​​

​​【Springboot】注解@ConfigurationProperties让配置整齐而简单 - 知乎​​


举报

相关推荐

0 条评论