diff --git a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java index 461fe14fa..a65c41808 100644 --- a/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.java +++ b/spring-cloud-context/src/main/java/org/springframework/cloud/bootstrap/config/PropertySourceBootstrapConfiguration.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. @@ -34,6 +34,8 @@ import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.boot.context.properties.bind.Binder; +import org.springframework.boot.context.properties.bind.PropertySourcesPlaceholdersResolver; +import org.springframework.boot.context.properties.source.ConfigurationPropertySource; import org.springframework.boot.logging.LogFile; import org.springframework.boot.logging.LoggingInitializationContext; import org.springframework.boot.logging.LoggingSystem; @@ -46,6 +48,7 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.event.ContextRefreshedEvent; import org.springframework.core.Ordered; +import org.springframework.core.ResolvableType; import org.springframework.core.annotation.AnnotationAwareOrderComparator; import org.springframework.core.env.AbstractEnvironment; import org.springframework.core.env.CompositePropertySource; @@ -54,13 +57,13 @@ import org.springframework.core.env.Environment; import org.springframework.core.env.MutablePropertySources; import org.springframework.core.env.PropertySource; -import org.springframework.util.StringUtils; import static org.springframework.cloud.bootstrap.encrypt.AbstractEnvironmentDecrypt.DECRYPTED_PROPERTY_SOURCE_NAME; import static org.springframework.core.env.StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME; /** * @author Dave Syer + * @author Yanming Zhou * */ @Configuration(proxyBeanMethods = false) @@ -294,6 +297,7 @@ private List addActiveProfilesTo(List profiles, PropertySource> T addProfilesTo(T profiles, PropertySource propertySource, String property, ConfigurableEnvironment environment) { if (propertySource instanceof CompositePropertySource) { @@ -303,27 +307,19 @@ private > T addProfilesTo(T profiles, PropertySourc } } else { - Collections.addAll(profiles, getProfilesForValue(propertySource.getProperty(property), environment)); + // bootstrapProperties is loaded as package-private + // ConfigurationPropertySourcesPropertySource + ResolvableType requiredType = ResolvableType.forClassWithGenerics(PropertySource.class, + ResolvableType.forClassWithGenerics(Iterable.class, ConfigurationPropertySource.class)); + if (requiredType.isInstance(propertySource)) { + Binder binder = new Binder((Iterable) propertySource.getSource(), + new PropertySourcesPlaceholdersResolver(environment)); + binder.bind(property, Bindable.listOf(String.class)).ifBound(profiles::addAll); + } } return profiles; } - private String[] getProfilesForValue(Object property, ConfigurableEnvironment environment) { - final String value = (property == null ? null : property.toString()); - return property == null ? new String[0] : resolvePlaceholdersInProfiles(value, environment); - } - - private String[] resolvePlaceholdersInProfiles(String profiles, ConfigurableEnvironment environment) { - return Arrays.stream(StringUtils.tokenizeToStringArray(profiles, ",")).map(s -> { - if (s.startsWith("${") && s.endsWith("}")) { - return environment.resolvePlaceholders(s); - } - else { - return s; - } - }).toArray(String[]::new); - } - /* * The ConextRefreshedEvent gets called at the end of the boostrap phase after config * data is loaded during bootstrap. This will run and do an "initial fetch" of 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..413aecbee 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 { @@ -597,6 +598,19 @@ public void includeProfileFromBootstrapPropertySourceWithAppContext() { private void includeProfileFromBootstrapPropertySource(String... properties) { PropertySourceConfiguration.MAP.put("spring.profiles.include", "bar,baz"); + assertIncludeProfileFromBootstrapPropertySource(properties); + + PropertySourceConfiguration.MAP.clear(); + PropertySourceConfiguration.MAP.put("spring.profiles.include[0]", "bar"); + PropertySourceConfiguration.MAP.put("spring.profiles.include[1]", "baz"); + assertIncludeProfileFromBootstrapPropertySource(properties); + + PropertySourceConfiguration.MAP.clear(); + PropertySourceConfiguration.MAP.put("spring.profiles.include", "${ENVIRONMENT_PROFILE_NAME:bar,baz}"); + assertIncludeProfileFromBootstrapPropertySource(properties); + } + + private void assertIncludeProfileFromBootstrapPropertySource(String... properties) { this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) .properties(properties) .profiles("foo") @@ -622,13 +636,25 @@ public void activeProfileFromBootstrapPropertySourceWithAppContext() { private void activeProfileFromBootstrapPropertySource(String... properties) { PropertySourceConfiguration.MAP.put("spring.profiles.active", "bar,baz"); + assertActiveProfileFromBootstrapPropertySource(properties); + + PropertySourceConfiguration.MAP.clear(); + PropertySourceConfiguration.MAP.put("spring.profiles.active[0]", "bar"); + PropertySourceConfiguration.MAP.put("spring.profiles.active[1]", "baz"); + assertActiveProfileFromBootstrapPropertySource(properties); + + PropertySourceConfiguration.MAP.clear(); + PropertySourceConfiguration.MAP.put("spring.profiles.active", "${ENVIRONMENT_PROFILE_NAME:bar,baz}"); + assertActiveProfileFromBootstrapPropertySource(properties); + } + + private void assertActiveProfileFromBootstrapPropertySource(String... properties) { this.context = new SpringApplicationBuilder().web(WebApplicationType.NONE) .properties(properties) .profiles("foo") .sources(BareConfiguration.class) .run(); then(this.context.getEnvironment().acceptsProfiles("baz", "bar", "foo")).isTrue(); - } @Test