From 22762f200462e4c380b73a5a67f4022dd7f30a12 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Mon, 23 Dec 2013 13:14:05 +0000 Subject: [PATCH] Adjust @PropertySource handling so @Conditionals are accounted for User can now do this, for instance: @Configuration @PropertySource("classpath:my.properties") public class MainConfiguration {} @Configuration @PropertySource("classpath:foo.properties") @Profile("foo") public class FooConfiguration {} and the "foo" properties ar eonly loaded in the "foo" profile. --- ...nfigFileApplicationContextInitializer.java | 57 ++++++++++++++++--- ...ileApplicationContextInitializerTests.java | 44 ++++++++++++++ 2 files changed, 92 insertions(+), 9 deletions(-) diff --git a/spring-boot/src/main/java/org/springframework/boot/context/initializer/ConfigFileApplicationContextInitializer.java b/spring-boot/src/main/java/org/springframework/boot/context/initializer/ConfigFileApplicationContextInitializer.java index 5438b3d01a..7130ba3974 100644 --- a/spring-boot/src/main/java/org/springframework/boot/context/initializer/ConfigFileApplicationContextInitializer.java +++ b/spring-boot/src/main/java/org/springframework/boot/context/initializer/ConfigFileApplicationContextInitializer.java @@ -28,6 +28,7 @@ import java.util.Random; import java.util.Set; import org.springframework.beans.PropertyValues; +import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplicationInitializer; import org.springframework.boot.bind.PropertySourcesPropertyValues; @@ -38,6 +39,7 @@ import org.springframework.boot.config.YamlPropertySourceLoader; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.EnvironmentAware; +import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; import org.springframework.context.annotation.PropertySources; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; @@ -150,7 +152,7 @@ public class ConfigFileApplicationContextInitializer implements for (AnnotationAttributes propertySource : attributesForRepeatable( new StandardAnnotationMetadata(type), PropertySources.class, org.springframework.context.annotation.PropertySource.class)) { - this.propertySourceAnnotations.add( + this.propertySourceAnnotations.add(type, propertySource.getStringArray("value"), propertySource.getBoolean("ignoreResourceNotFound"), propertySource.getString("name")); @@ -255,11 +257,16 @@ public class ConfigFileApplicationContextInitializer implements ResourceLoader resourceLoader, String location, String profile) { location = environment.resolvePlaceholders(location); String suffix = "." + StringUtils.getFilenameExtension(location); + Class type = this.propertySourceAnnotations.configuration(location); if (StringUtils.hasLength(profile)) { location = location.replace(suffix, "-" + profile + suffix); } + if (isPropertySourceAnnotationOnExcludedType(profile, type, location)) { + return null; + } + List loaders = new ArrayList(); loaders.add(new PropertiesPropertySourceLoader()); if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) { @@ -289,6 +296,30 @@ public class ConfigFileApplicationContextInitializer implements return propertySource; } + private boolean isPropertySourceAnnotationOnExcludedType(String profile, + Class type, String location) { + if (type == null) { + // No configuration class to worry about, just a vanilla properties location + return false; + } + if (StringUtils.hasText(profile) + && !this.propertySourceAnnotations.locations().contains(location)) { + // We are looking for profile specific properties and this one isn't + // explicitly asked for in propertySourceAnnotations + return true; + } + AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader( + new DefaultListableBeanFactory(), this.environment); + int before = reader.getRegistry().getBeanDefinitionCount(); + reader.register(type); + int after = reader.getRegistry().getBeanDefinitionCount(); + if (after == before) { + // The configuration class was @Conditional and excluded + return true; + } + return false; + } + private PropertySource getPropertySource(String name, Resource resource, String profile, List loaders) { String key = resource.getDescription() + (profile == null ? "" : "#" + profile); @@ -364,25 +395,33 @@ public class ConfigFileApplicationContextInitializer implements private Map names = new HashMap(); + private Map> configs = new HashMap>(); + private Map ignores = new HashMap(); - public void add(String[] locations, boolean ignoreResourceNotFound, String name) { + public void add(Class source, String[] locations, + boolean ignoreResourceNotFound, String name) { this.locations.addAll(Arrays.asList(locations)); if (StringUtils.hasText(name)) { for (String location : locations) { this.names.put(location, name); } - for (String location : locations) { - boolean reallyIgnore = ignoreResourceNotFound; - if (this.ignores.containsKey(location)) { - // Only if they all ignore this location will it be ignored - reallyIgnore &= this.ignores.get(location); - } - this.ignores.put(location, reallyIgnore); + } + for (String location : locations) { + boolean reallyIgnore = ignoreResourceNotFound; + if (this.ignores.containsKey(location)) { + // Only if they all ignore this location will it be ignored + reallyIgnore &= this.ignores.get(location); } + this.ignores.put(location, reallyIgnore); + this.configs.put(location, source); } } + public Class configuration(String location) { + return this.configs.get(location); + } + public boolean ignoreResourceNotFound(String location) { return this.ignores.containsKey(location) ? this.ignores.get(location) : false; diff --git a/spring-boot/src/test/java/org/springframework/boot/context/initializer/ConfigFileApplicationContextInitializerTests.java b/spring-boot/src/test/java/org/springframework/boot/context/initializer/ConfigFileApplicationContextInitializerTests.java index d85113177e..dc0b7d66f9 100644 --- a/spring-boot/src/test/java/org/springframework/boot/context/initializer/ConfigFileApplicationContextInitializerTests.java +++ b/spring-boot/src/test/java/org/springframework/boot/context/initializer/ConfigFileApplicationContextInitializerTests.java @@ -24,6 +24,7 @@ import org.junit.Test; import org.springframework.boot.SpringApplication; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Profile; import org.springframework.context.annotation.PropertySource; import org.springframework.context.support.StaticApplicationContext; import org.springframework.core.env.MapPropertySource; @@ -34,6 +35,7 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; /** @@ -196,6 +198,35 @@ public class ConfigFileApplicationContextInitializerTests { context.close(); } + @Test + public void propertySourceAnnotationInProfile() throws Exception { + SpringApplication application = new SpringApplication( + WithPropertySourceInProfile.class); + application.setWebEnvironment(false); + ConfigurableApplicationContext context = application + .run("--spring.profiles.active=myprofile"); + String property = context.getEnvironment().getProperty("my.property"); + assertThat(property, equalTo("frompropertiesfile")); + assertNotNull(context.getEnvironment().getPropertySources() + .get("classpath:/enableprofile.properties")); + assertNull(context.getEnvironment().getPropertySources() + .get("classpath:/enableprofile-myprofile.properties")); + context.close(); + } + + @Test + public void propertySourceAnnotationAndProfile() throws Exception { + SpringApplication application = new SpringApplication( + WithPropertySourceAndProfile.class); + application.setWebEnvironment(false); + ConfigurableApplicationContext context = application.run(); + String property = context.getEnvironment().getProperty("my.property"); + assertThat(property, equalTo(null)); + assertNull(context.getEnvironment().getPropertySources() + .get("classpath:/enableprofile-myprofile.properties")); + context.close(); + } + @Test public void propertySourceAnnotationMultipleLocations() throws Exception { SpringApplication application = new SpringApplication( @@ -242,6 +273,19 @@ public class ConfigFileApplicationContextInitializerTests { } + @Configuration + @PropertySource("classpath:/enableprofile.properties") + protected static class WithPropertySourceInProfile { + + } + + @Configuration + @PropertySource("classpath:/enableprofile-myprofile.properties") + @Profile("myprofile") + protected static class WithPropertySourceAndProfile { + + } + @Configuration @PropertySource({ "classpath:/specificlocation.properties", "classpath:/moreproperties.properties" })