From 2dc387fe3ba8e06f30db69116f457810c4f8c7cc Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 7 Feb 2025 10:19:10 +0800 Subject: [PATCH] PropertySourceLocator should honer `spring.config.activate.*` See https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files.activation-properties Signed-off-by: Yanming Zhou --- .../config/PropertySourceLocator.java | 23 +++++- .../config/BootstrapConfigurationTests.java | 75 ++++++++++++++++++- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceLocator.java b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceLocator.java index 2e68699e4..79da73bc9 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceLocator.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceLocator.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,8 +21,10 @@ import java.util.Collections; import java.util.List; +import org.springframework.boot.cloud.CloudPlatform; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.Environment; +import org.springframework.core.env.Profiles; import org.springframework.core.env.PropertySource; /** @@ -31,6 +33,7 @@ * starting. * * @author Dave Syer + * @author Yanming Zhou * */ public interface PropertySourceLocator { @@ -55,15 +58,29 @@ static Collection> locateCollection(PropertySourceLocator loca Collection> sources = ((CompositePropertySource) propertySource).getPropertySources(); List> filteredSources = new ArrayList<>(); for (PropertySource p : sources) { - if (p != null) { + if (p != null && shouldActivatePropertySource(p, environment)) { filteredSources.add(p); } } return filteredSources; } else { - return List.of(propertySource); + return shouldActivatePropertySource(propertySource, environment) ? List.of(propertySource) + : Collections.emptyList(); } } + private static boolean shouldActivatePropertySource(PropertySource ps, Environment environment) { + String onProfile = (String) ps.getProperty("spring.config.activate.on-profile"); + if ((onProfile != null) && !environment.acceptsProfiles(Profiles.of(onProfile))) { + return false; + } + String onCloudPlatform = (String) ps.getProperty("spring.config.activate.on-cloud-platform"); + if (onCloudPlatform != null) { + CloudPlatform cloudPlatform = CloudPlatform.getActive(environment); + return cloudPlatform != null && cloudPlatform.name().equalsIgnoreCase(onCloudPlatform); + } + return true; + } + } diff --git a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java index a9ac91328..67c9fad02 100644 --- a/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java +++ b/spring-cloud-context/src/test/java/org/springframework/cloud/bootstrap/config/BootstrapConfigurationTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2020 the original author or authors. + * Copyright 2012-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,7 @@ /** * @author Dave Syer + * @author Yanming Zhou * */ public class BootstrapConfigurationTests { @@ -740,6 +741,78 @@ void activeAndIncludeProfileFromBootstrapPropertySource_WhenMultiplePlacesHaveAc .anyMatch("local"::equals)).isTrue(); } + @Test + void activatedOnProfile() { + PropertySourceConfiguration.MAP.put("stage", "dev"); + PropertySourceConfiguration.MAP.put("spring.config.activate.on-profile", "dev"); + String[] properties = new String[] { "spring.config.use-legacy-processing=true" }; + this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) + .properties(properties) + .sources(BareConfiguration.class) + .run("--spring.profiles.active=dev"); + then(this.context.getEnvironment().getProperty("stage")).isEqualTo("dev"); + } + + @Test + void notActivatedOnNoActiveProfile() { + PropertySourceConfiguration.MAP.put("stage", "dev"); + PropertySourceConfiguration.MAP.put("spring.config.activate.on-profile", "dev"); + String[] properties = new String[] { "spring.config.use-legacy-processing=true" }; + this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) + .properties(properties) + .sources(BareConfiguration.class) + .run(); + then(this.context.getEnvironment().getProperty("stage")).isNotEqualTo("dev"); + } + + @Test + void notActivatedOnMismatchedProfile() { + PropertySourceConfiguration.MAP.put("stage", "dev"); + PropertySourceConfiguration.MAP.put("spring.config.activate.on-profile", "dev"); + String[] properties = new String[] { "spring.config.use-legacy-processing=true" }; + this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) + .properties(properties) + .sources(BareConfiguration.class) + .run("--spring.profiles.active=prod"); + then(this.context.getEnvironment().getProperty("stage")).isNotEqualTo("dev"); + } + + @Test + void activatedOnCloudPlatform() { + PropertySourceConfiguration.MAP.put("cloud", "kubernetes"); + PropertySourceConfiguration.MAP.put("spring.config.activate.on-cloud-platform", "kubernetes"); + String[] properties = new String[] { "spring.config.use-legacy-processing=true" }; + this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) + .properties(properties) + .sources(BareConfiguration.class) + .run("--spring.main.cloud-platform=kubernetes"); + then(this.context.getEnvironment().getProperty("cloud")).isEqualTo("kubernetes"); + } + + @Test + void notActivatedOnNoActiveCloudPlatform() { + PropertySourceConfiguration.MAP.put("cloud", "kubernetes"); + PropertySourceConfiguration.MAP.put("spring.config.activate.on-cloud-platform", "kubernetes"); + String[] properties = new String[] { "spring.config.use-legacy-processing=true" }; + this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) + .properties(properties) + .sources(BareConfiguration.class) + .run(); + then(this.context.getEnvironment().getProperty("cloud")).isNotEqualTo("kubernetes"); + } + + @Test + void notActivatedOnMismatchedCloudPlatform() { + PropertySourceConfiguration.MAP.put("cloud", "kubernetes"); + PropertySourceConfiguration.MAP.put("spring.config.activate.on-cloud-platform", "kubernetes"); + String[] properties = new String[] { "spring.config.use-legacy-processing=true" }; + this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) + .properties(properties) + .sources(BareConfiguration.class) + .run("--spring.main.cloud-platform=heroku"); + then(this.context.getEnvironment().getProperty("cloud")).isNotEqualTo("kubernetes"); + } + @Configuration(proxyBeanMethods = false) @EnableConfigurationProperties protected static class BareConfiguration {