Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)

Spring Boot配置

在spring中我们都知道所有配置定义在配置文件application.yml中我们就可以通过注解获取到。Spring 中对所有配置管理都有一个统一的上层接口

  • Environment

实现类图Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)可以看到实现类是非常多的。不过实际所有的配置获取都是封装在最上层的接口PropertyResolver中的Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)

这里需要注意的是PropertyResolver的核心实现类PropertySourcesPropertyResolverSpring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)

PropertySourcesPropertyResolver中拥有的PropertySources最后使用的也还是PropertySource类,通过遍历PropertySource集合Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)PropertySource最终是通过拥有一个泛型T source获取最终的属性Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)所以这里可以看到我们所有的资源都是一个PropertySource需要注意的是,PropertySource之间是有优先级顺序的,如果有一个Key在多个PropertySource中都存在,那么在前面的PropertySource优先。

大致获取的原理这里引用apollo的一张图Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)这张图就是比较清晰的

简单测试使用

spring boot 版本 2.6.8

yaml 配置一个name属性

name: 1214
@RestController
public class EnvironementController {
    @Autowired
    Environment environment;
    
 @Value("${name}")
    private String name;

    @GetMapping("/name")
    public String env(){
        System.out.println(name);
        return environment.getProperty("name");
    }
}

无论是使用@Value还是Environment都能获取到我们的自定义属性

然后调用接口就能获取到我们配置中的属性了Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)

Spring Cloud自定义配置文件获取

在了解了上面的原理及基本使用之后我们可以就可以自定义配置文件了。核心思路就是通过读取文件然后加载到PropertySource中去。而Spring Cloud刚好提供类这方面的扩展,Spring Cloud 提供了PropertySourceLocator接口供我们加载自定义配置成PropertySourceSpring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)

我们这里只需要实现locate即可

按这个方式我们来自定义配置试试

1. 引入依赖

 <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>    
        <spring-cloud.version>2021.0.2</spring-cloud.version>
        <spring-boot.version>2.7.0</spring-boot.version>

    </properties>

  <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-context</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
  
  <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>      
        </dependencies>

    </dependencyManagement>

注意spring Cloud 2020版本后需要手动引入依赖 spring-cloud-starter-bootstrap

2. 自定义配置

2.1 自定义PropertySource,这里我们直接使用Spring 提供的MapPropertySource

package com.zou.config;

import java.util.Map;

import org.springframework.core.env.MapPropertySource;

/**
 *@author : wh
 *@date : 2022/7/12 09:54
 *@description:
 */

public class ZouMapPropertySource extends MapPropertySource {


 /**
  * Create a new {@code MapPropertySource} with the given name and {@code Map}.
  *
  * @param name   the associated name
  * @param source the Map source (without {@code null} values in order to get
  *               consistent {@link #getProperty} and {@link #containsProperty} behavior)
  */

 public ZouMapPropertySource(String name, Map<String, Object> source) {
  super(name, source);
 }
 
 
}

2.2 自定义PropertySourceLocator

package com.zou.config;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.boot.json.JsonParser;
import org.springframework.boot.json.JsonParserFactory;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.annotation.Order;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;

/**
 * @author : wh
 * @date : 2022/7/12 09:56
 * @description:
 */

@Order(0)
public class ZouJsonPropertySourceLocator implements PropertySourceLocator {

 @Override
 public PropertySource<?> locate(Environment environment) {
  return new ZouMapPropertySource
    ("ZouMapPropertySource", mapPropertySource());
 }

 private Map<String, Object> mapPropertySource() {
  Map<String, Object> result = new HashMap<>();
  JsonParser parser = JsonParserFactory.getJsonParser();
  Map<String, Object> fileMap = parser.parseMap(readFile());
  processNestMap("", result, fileMap);
  return result;
 }

 /**
  * 读取配置文件 zou.json
  *
  * @return
  */

 private String readFile() {
  List<String> lines;
  try {
   lines = Files.readAllLines(Paths.get("src/main/resources/zou.json"), StandardCharsets.UTF_8);
  }
  catch (IOException e) {
   throw new RuntimeException(e);
  }
  StringBuilder sb = new StringBuilder();
  for (String line : lines) {
   sb.append(line);
  }
  return sb.toString();
 }

 private void processNestMap(String prefix, Map<String, Object> result, Map<String, Object> fileMap) {
  if (prefix.length() > 0) {
   prefix += ".";
  }
  for (Map.Entry<String, Object> entrySet : fileMap.entrySet()) {
   if (entrySet.getValue() instanceof Map) {
    processNestMap(prefix + entrySet.getKey(), result, (Map<String, Object>) entrySet.getValue());
   }
   else {
    result.put(prefix + entrySet.getKey(), entrySet.getValue());
   }
  }
 }

}

2.3  自定义配置Bean config

@Configuration(proxyBeanMethods = false)
public class ZouConfiguration {

 @Bean
 public ZouJsonPropertySourceLocator zouJsonPropertySourceLocator(){
  return new ZouJsonPropertySourceLocator();
 }
}

2.4 定义BootstrapConfiguration配置

resources 添加spring.factories配置文件

org.springframework.cloud.bootstrap.BootstrapConfiguration=
com.zou.config.ZouConfiguration

3. 测试

这里简单定义一个我们自己的配置文件zou.jsonSpring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)

{
  "name""xiaozou"
}

定义一个测试controller

@RestController
@RequestMapping("test/v1")
public class ZouController {
 @Autowired
    Environment environment;

    @Value("${name:1}")
    private String name;

    @GetMapping("/name")
    public String env(){
        System.out.println(name);
        return environment.getProperty("name");
    }
}

Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)可以看到我们自定义配置是生效了的

总结

Spring Cloud 整合自定义配置还是比较容易的,核心还是自定义一个ZouJsonPropertySourceLocator然后加载PropertySource到Spring中。这里我们整合的是本地文件,其实如果要整合远程配置中心也是类似的,只不过获取文件就不是读取本地配置文件,而是通过http读取远程配置文件然后构造出一个PropertySource放入Spring容器中。后续有机会我们对nacos整合Spring Cloud源码进行分析


原文始发于微信公众号(小奏技术):Spring Boot、Spring Cloud 自定义配置文件(如何整合配置中心)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/29836.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!