Springboot 获取配置信息的优雅实践

闲来无事,翻看源码时发现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>

https://juejin.im/post/5e36b4486fb9a02ffc376ba0

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论