闲来无事,翻看源码时发现Springboot在获取配置信息方面的实践十分优雅,值得效仿。
之前在介绍 Aware家族接口时,其实提到过获取配置信息的解决方案,但是无论是实现EnvironmentAware接口,还是直接注入Environment的bean,本质上相同,获取多个配置信息时,力不从心。
// 本文借鉴了以下源码
org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration
org.springframework.boot.autoconfigure.http.HttpProperties
首先创建properties文件
以spring.customize为前缀定义了如下三个属性

根据属性定义一个JavaBean
@ConfigurationProperties注解可以直接确认JavaBean属性与配置信息的映射关系,注解的prefix属性用于指定需要映射的配置信息的前缀。代码中我并没有指定前缀信息为"spring.customize",而是指定为"spring",这里是有基于代码层次的考究的。CustomizeProperties其实还包含了一个静态内部类Customize。官方文档(B3.1)对自身属性及其嵌套属性有明确说明。
package com.springboot.autoconfigure.properties;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "spring")
public class CustomizeProperties {
private final Customize customize = new Customize();
public Customize getCustomize() {
return customize;
}
public static class Customize {
private String address;
private String port;
private boolean enable;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
}
}
定义与之对应的配置类
@EnableConfigurationProperties注解的作用是:使 使用了@ConfigurationProperties注解标注的类生效。注意到了吗:之前的CustomizeProperties并没有使用@Component注解,依然可以注入到IOC容器中。在没有生效时,容器中是不允许CustomizeProperties组件存在的。
package com.springboot.autoconfigure.properties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
@Configuration
@EnableConfigurationProperties(CustomizeProperties.class)
public class CustomizeAutoConfiguration {
private CustomizeProperties.Customize customize;
/**
* 构造注入,当有且仅有一个参数时,
* 即使没有显式的@Autowired依然可以装配到目的Bean
*/
public CustomizeAutoConfiguration(CustomizeProperties customizeProperties) {
this.customize = customizeProperties.getCustomize();
}
/**
* 将获取到的配置信息收集到List
* 这里没有任何意义,只是为了方便打印
*/
@Bean
public ArrayList arrayList () {
ArrayList<Object> list = new ArrayList<>();
list.add(customize.getAddress());
list.add(customize.getPort());
list.add(customize.isEnable());
return list;
}
}
定义配置类
package com.springboot.autoconfigure.properties;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:application-dev.properties")
@ComponentScan("com.springboot.autoconfigure.properties")
public class Config {
}
定义启动类
package com.springboot.autoconfigure.properties;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import java.util.ArrayList;
public class MainCustomizeProperties {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);
ArrayList<Object> list = context.getBean(ArrayList.class);
list.forEach(System.out::println);
}
}
如果获取配置信息成功我们是可以看到打印信息的。

spring-configuration-metadata.json
相信很多人是第一次见到这个文件名,metadata Spring官方称其为元数据,那以此类推spring-configuration-metadata.json就是定义元数据的json文件。其实细心的你应该已经发现端倪,第一张图片配置信息下方居然没有波浪线提醒。这就表明了此三条配置信息是允许链接的。
配置信息与对应的JavaBean取得关联后,JavaBean也会有变化。属性对应的setter方法,有一个小图标提示。
配置信息与JavaBean产生联系,背后就是spring-configuration-metadata.json文件悄悄牵下了红线。
具体的配置规则上文提到的官方文档有详细说明。
我贴一下我的配置信息。
{
"groups": [
{
"name": "spring",
"type": "com.springboot.autoconfigure.properties.CustomizeProperties",
"sourceType": "com.springboot.autoconfigure.properties.CustomizeProperties"
},
{
"name": "spring.customize",
"type": "com.springboot.autoconfigure.properties.CustomizeProperties$Customize",
"sourceType": "com.springboot.autoconfigure.properties.CustomizeProperties",
"sourceMethod": "getCustomize()"
}
],
"properties": [
{
"name": "spring.customize.address",
"type": "java.lang.String",
"sourceType": "com.springboot.autoconfigure.properties.CustomizeProperties$Customize"
},
{
"name": "spring.customize.enable",
"type": "java.lang.Boolean",
"sourceType": "com.springboot.autoconfigure.properties.CustomizeProperties$Customize",
"defaultValue": false
},
{
"name": "spring.customize.port",
"type": "java.lang.String",
"sourceType": "com.springboot.autoconfigure.properties.CustomizeProperties$Customize"
}
],
"hints": []
}
其实如果你实在不愿意配置,加上依赖,自动生成亦可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true </optional>
</dependency>