Spring Cloud Alibaba (https://gitee.com/mirrors/Spring-Cloud-Alibaba)示例代码 spring-cloud-alibaba-examples 的 Integerated-example 项目中,integrated-praise-consumer 模块中,在YamlConfigParser类中,实现了从Nacos配置中心读取Spring boot程序的 yaml 格式配置文件内容的功能。

这个类的代码如下:

public class YamlConfigParser {
    @Autowired
    private NacosConfigManager nacosConfigManager;

    private Integer pullInterval = 4000;
    private Integer pullBatchSize = 4;

    private Integer minThread = 2; // 设置最小消费线程数
    private Integer maxThread = 32; // 设置最大消费线程数
    private String consumerGroup; // 消费者组
    private String  nameSrvAddr; // 命名服务器地址和端口号
    private String topic; // 消息主题

    public YamlConfigParser() {
    }

    public void getConfig(){
        String cfg = "";
        try {
            ConfigService configService = nacosConfigManager.getConfigService();
            cfg = configService.getConfig("integrated-consumer.yaml", "integrated-example", 2000);
            System.out.println("获取到配置信息--------------");
            System.out.println(cfg);
        }catch (NacosException e){
            e.printStackTrace();
        }
        if(cfg.length() == 0)
            return ;

        // 将字符串转换为字节数组
        byte[] bytes = cfg.getBytes(StandardCharsets.UTF_8);
        Yaml yaml = new Yaml();
        try (InputStream in = new ByteArrayInputStream(bytes)) {
            Map<String, Object> config = yaml.load(in);

            // 需要按照配置文件逐层解析并访问配置信息
            Map<String, Object> springConfig = (Map<String, Object>) config.get("spring");
            Map<String, Object> cloudConfig = (Map<String, Object>) springConfig.get("cloud");
            Map<String, Object> streamConfig = (Map<String, Object>) cloudConfig.get("stream");
            Map<String, Object> bindingsConfig = (Map<String, Object>) streamConfig.get("bindings");
            Map<String, Object> inputConfig = (Map<String, Object>) bindingsConfig.get("praise-input");

            // topic = (String) config.get("spring.cloud.stream.bindings.praise-input.destination"); // 不支持这种用法,取不到值
            topic = (String) inputConfig.get("destination");
            consumerGroup = (String) inputConfig.get("group");

            Map<String, Object> rocketmqConfig = (Map<String, Object>) streamConfig.get("rocketmq");
            Map<String, Object> binderConfig = (Map<String, Object>) rocketmqConfig.get("binder");
            nameSrvAddr = (String)binderConfig.get("name-server");

            Map<String, Object> mqbindingsConfig = (Map<String, Object>) rocketmqConfig.get("bindings");
            Map<String, Object> mqpraiseinputConfig = (Map<String, Object>) mqbindingsConfig.get("praise-input");
            Map<String, Object> consumerinputConfig = (Map<String, Object>) mqpraiseinputConfig.get("consumer");

            pullInterval = (Integer)consumerinputConfig.get("pullInterval");
            pullBatchSize = (Integer)consumerinputConfig.get("pullBatchSize");

            // 输出配置信息
            System.out.println("nameSrvAddr: " + nameSrvAddr);
            System.out.println("consumerGroup: " + consumerGroup);
            System.out.println("topic: " + topic);
            System.out.println("pullInterval: " + pullInterval);
            System.out.println("pullBatchSize: " + pullBatchSize);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Integer getPullInterval() {
        return pullInterval;
    }
    public void setPullInterval(Integer pullInterval) {
        this.pullInterval = pullInterval;
    }
    public Integer getPullBatchSize() {
        return pullBatchSize;
    }
    public void setPullBatchSize(Integer pullBatchSize) {
        this.pullBatchSize = pullBatchSize;
    }
    public Integer getMinThread() {
        return minThread;
    }
    public void setMinThread(Integer minThread) {
        this.minThread = minThread;
    }
    public Integer getMaxThread() {
        return maxThread;
    }
    public void setMaxThread(Integer maxThread) {
        this.maxThread = maxThread;
    }
    public String getConsumerGroup() {
        return consumerGroup;
    }
    public void setConsumerGroup(String consumerGroup) {
        this.consumerGroup = consumerGroup;
    }
    public String getNameSrvAddr() {
        return nameSrvAddr;
    }
    public void setNameSrvAddr(String nameSrvAddr) {
        this.nameSrvAddr = nameSrvAddr;
    }
    public String getTopic() {
        return topic;
    }
    public void setTopic(String topic) {
        this.topic = topic;
    }
}

读取的 integrated-consumer.yaml 文件内容如下:

spring:
  datasource:
    url: jdbc:mysql://integrated-mysql:3306/integrated_praise?useSSL=false&characterEncoding=utf8
  cloud:
    stream:
      bindings:
        praise-input:
          destination: PRAISE-TOPIC-01
          content-type: application/json
          group: praise-consumer-group-PRAISE-TOPIC-01
      rocketmq:
        binder:
          name-server: rocketmq:9876
        bindings:
          praise-input:
            consumer:
              pullInterval: 4000
              pullBatchSize: 4

代码中getConfig()方法功能是从Nacos配置中心获取名为integrated-consumer.yaml的配置文件,并将其内容解析为Java对象,然后从这些对象中提取特定的配置信息。以下是该代码的主要步骤和功能:

  1. 获取配置:使用ConfigService从Nacos配置中心获取名为integrated-consumer.yaml的配置,配置文件的命名空间(namespace)是integrated-example,并设置超时时间为2000毫秒。

ConfigService configService = nacosConfigManager.getConfigService();
cfg = configService.getConfig("integrated-consumer.yaml", "integrated-example", 2000);

   2.配置解析:将获取到的字符串配置cfg转换为字节数组,然后使用Yaml库将其解析为Map<String, Object>对象。

byte[] bytes = cfg.getBytes(StandardCharsets.UTF_8);
Yaml yaml = new Yaml();
try (InputStream in = new ByteArrayInputStream(bytes)) {
Map<String, Object> config = yaml.load(in);
}

3.逐层解析配置:通过逐层访问Map对象,提取特定的配置信息,如topic、consumerGroup和nameSrvAddr等。

Map<String, Object> springConfig = (Map<String, Object>) config.get("spring");
Map<String, Object> cloudConfig = (Map<String, Object>) springConfig.get("cloud");
// ... 更多的逐层解析 ...
topic = (String) inputConfig.get("destination");
consumerGroup = (String) inputConfig.get("group");
nameSrvAddr = (String)binderConfig.get("name-server");

需要注意的是,这段代码假设YAML配置文件的结构是已知的,并且能够通过链式调用get方法访问到相应的配置信息。如果配置文件的结构发生变化,或者某个键不存在,这段代码将会抛出NullPointerException。

此外,这段代码还展示了如何从一个复杂的嵌套结构中提取特定的配置值,这在处理复杂的配置文件时是非常常见的。

代码中

// 不支持这种用法,取不到值

topic = (String) config.get("spring.cloud.stream.bindings.praise-input.destination");

这是尝试通过直接拼接键名来获取配置值的方式,证明是不可行的,必须逐层解析配置对象来获取值。

更多推荐