alibaba / nacos

an easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications.
https://nacos.io
Apache License 2.0
30.04k stars 12.8k forks source link

spring boot profile配置问题 #12524

Closed zevinc closed 4 weeks ago

zevinc commented 1 month ago

由于项目的配置项比较少,我不想走多Profile文件方式,而是想走多Profile文档块方式,要怎么做?

nacos默认配置方式: application.yaml application-dev.yaml application-test.yaml

我想要的: application.yaml


---
spring:
  profiles: dev
---
spring:
  profiles: test
---
spring:
  profiles: prod
fuhouyu commented 4 weeks ago

这是由SpringBoot提供的,分环境文件是方便管理。 如果不想以这种方式,可以在application.yaml中写一个默认的配置,后续在启动时添加-D参数以替换

zevinc commented 4 weeks ago

这是由SpringBoot提供的,分环境文件是方便管理。 如果不想以这种方式,可以在application.yaml中写一个默认的配置,后续在启动时添加-D参数以替换

我在配置中心那里定义dataId=application.yaml,content如下:

---
spring:
  profiles: dev
xxx.host: 127.0.0.1
---
spring:
  profiles: test
xxx.host: 127.0.0.2
---
spring:
  profiles: prod
xxx.host: 127.0.0.3

实际上是只有最后一个文档块配置才会生效,通过spring.profiles来区分配置没有生效,我想在配置中心那里也使用这个特性,而不是拆分为多个文件(诸如这样的:application.yaml、application-dev.yaml、application-test.yaml)。

XiaZhouxx commented 4 weeks ago

这是由SpringBoot提供的,分环境文件是方便管理。 如果不想以这种方式,可以在application.yaml中写一个默认的配置,后续在启动时添加-D参数以替换

我在配置中心那里定义dataId=application.yaml,content如下:

---
spring:
  profiles: dev
xxx.host: 127.0.0.1
---
spring:
  profiles: test
xxx.host: 127.0.0.2
---
spring:
  profiles: prod
xxx.host: 127.0.0.3

实际上是只有最后一个文档块配置才会生效,通过spring.profiles来区分配置没有生效,我想在配置中心那里也使用这个特性,而不是拆分为多个文件(诸如这样的:application.yaml、application-dev.yaml、application-test.yaml)。

老哥你是什么版本, 用的是哪个SDK? 我用com.alibaba.cloud 最新版本是有这个特性, 你这个问题应该去对应的sdk社区问下吧, Nacos应该不负责这些应用层的逻辑

zevinc commented 4 weeks ago

这是由SpringBoot提供的,分环境文件是方便管理。 如果不想以这种方式,可以在application.yaml中写一个默认的配置,后续在启动时添加-D参数以替换

我在配置中心那里定义dataId=application.yaml,content如下:

---
spring:
  profiles: dev
xxx.host: 127.0.0.1
---
spring:
  profiles: test
xxx.host: 127.0.0.2
---
spring:
  profiles: prod
xxx.host: 127.0.0.3

实际上是只有最后一个文档块配置才会生效,通过spring.profiles来区分配置没有生效,我想在配置中心那里也使用这个特性,而不是拆分为多个文件(诸如这样的:application.yaml、application-dev.yaml、application-test.yaml)。

老哥你是什么版本, 用的是哪个SDK? 我用com.alibaba.cloud 最新版本是有这个特性, 你这个问题应该去对应的sdk社区问下吧, Nacos应该不负责这些应用层的逻辑

版本: "spring-boot" : "2.7.0", "spring-cloud" : "2021.0.5", "spring-cloud-alibaba" : "2021.0.5.0" 服务端nacos版本是2.2.0,确实没有生效。

我找到了源码中解析配置数据相关代码,项目里暂时修改了源码中com.alibaba.cloud.nacos.client.NacosPropertySource#getSourceMap(String, String, List<PropertySource<?>>)就好了。

修改前:

    private static Map<String, Object> getSourceMap(String group, String dataId,
            List<PropertySource<?>> propertySources) {
                //.........

        Map<String, Object> sourceMap = new LinkedHashMap<>();
        List<PropertySource<?>> otherTypePropertySources = new ArrayList<>();
        for (PropertySource<?> propertySource : propertySources) {
            if (propertySource == null) {
                continue;
            }
            if (propertySource instanceof MapPropertySource) {
                // If the Nacos configuration file uses "---" to separate property name,
                // propertySources will be multiple documents, and every document is a
                // map.
                // see org.springframework.boot.env.YamlPropertySourceLoader#load
                MapPropertySource mapPropertySource = (MapPropertySource) propertySource;
                Map<String, Object> source = mapPropertySource.getSource();
                sourceMap.putAll(source);
            }
            else {
                otherTypePropertySources.add(propertySource);
            }
        }

        //.........
    }

修改后:

  private static Map<String, Object> getSourceMap(String group, String dataId,
                                                    List<PropertySource<?>> propertySources) {
        //.........
        var activeProfileList = getActiveProfileList();//来自applicationContext.getEnvironment().getActiveProfiles()

        Map<String, Object> sourceMap = new LinkedHashMap<>();
        List<PropertySource<?>> otherTypePropertySources = new ArrayList<>();
        boolean profileSourceIsUse = false;
        for (PropertySource<?> propertySource : propertySources) {
            if (propertySource == null) {
                continue;
            }

            if (propertySource instanceof MapPropertySource) {
                // If the Nacos configuration file uses "---" to separate property name,
                // propertySources will be multiple documents, and every document is a
                // map.
                // see org.springframework.boot.env.YamlPropertySourceLoader#load
                MapPropertySource mapPropertySource = (MapPropertySource) propertySource;
                Map<String, Object> source = mapPropertySource.getSource();

                // If the document contains "spring.profiles" property
                if(source.containsKey("spring.profiles")) {
                    if(profileSourceIsUse) {
                        continue;
                    }

                    var profileList = new ArrayList<String>();

                    Object profiles = source.get("spring.profiles");
                    if(profiles instanceof String profile) {
                        profileList.add(profile);
                    }
                    else if(profiles instanceof Iterable profilesAsIterable) {
                        for (Object profile : profilesAsIterable) {
                            profileList.add((String) profile);
                        }
                    }

                    for (var profile : profileList) {
                        if(activeProfileList.contains(profile)) {
                            sourceMap.putAll(source);
                            profileSourceIsUse = true;
                            break;
                        }
                    }
                }
                // no profile
                else {
                    source.forEach((key, value) -> {
                        if(!sourceMap.containsKey(key)) {
                            sourceMap.put(key, value);
                        }
                    });
                }
            } else {
                otherTypePropertySources.add(propertySource);
            }
        }

      //.........
    }
KomachiSion commented 4 weeks ago

建议将这个issue转到spring cloud alibaba 社区咨询,这个问题应该纯粹的是spring/spring cloud的问题。