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.
pull/184/head
Dave Syer 11 years ago
parent 6c4ee0b05d
commit 22762f2004

@ -28,6 +28,7 @@ import java.util.Random;
import java.util.Set; import java.util.Set;
import org.springframework.beans.PropertyValues; import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationInitializer; import org.springframework.boot.SpringApplicationInitializer;
import org.springframework.boot.bind.PropertySourcesPropertyValues; 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.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EnvironmentAware; import org.springframework.context.EnvironmentAware;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader;
import org.springframework.context.annotation.PropertySources; import org.springframework.context.annotation.PropertySources;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAttributes;
@ -150,7 +152,7 @@ public class ConfigFileApplicationContextInitializer implements
for (AnnotationAttributes propertySource : attributesForRepeatable( for (AnnotationAttributes propertySource : attributesForRepeatable(
new StandardAnnotationMetadata(type), PropertySources.class, new StandardAnnotationMetadata(type), PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) { org.springframework.context.annotation.PropertySource.class)) {
this.propertySourceAnnotations.add( this.propertySourceAnnotations.add(type,
propertySource.getStringArray("value"), propertySource.getStringArray("value"),
propertySource.getBoolean("ignoreResourceNotFound"), propertySource.getBoolean("ignoreResourceNotFound"),
propertySource.getString("name")); propertySource.getString("name"));
@ -255,11 +257,16 @@ public class ConfigFileApplicationContextInitializer implements
ResourceLoader resourceLoader, String location, String profile) { ResourceLoader resourceLoader, String location, String profile) {
location = environment.resolvePlaceholders(location); location = environment.resolvePlaceholders(location);
String suffix = "." + StringUtils.getFilenameExtension(location); String suffix = "." + StringUtils.getFilenameExtension(location);
Class<?> type = this.propertySourceAnnotations.configuration(location);
if (StringUtils.hasLength(profile)) { if (StringUtils.hasLength(profile)) {
location = location.replace(suffix, "-" + profile + suffix); location = location.replace(suffix, "-" + profile + suffix);
} }
if (isPropertySourceAnnotationOnExcludedType(profile, type, location)) {
return null;
}
List<PropertySourceLoader> loaders = new ArrayList<PropertySourceLoader>(); List<PropertySourceLoader> loaders = new ArrayList<PropertySourceLoader>();
loaders.add(new PropertiesPropertySourceLoader()); loaders.add(new PropertiesPropertySourceLoader());
if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) { if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
@ -289,6 +296,30 @@ public class ConfigFileApplicationContextInitializer implements
return propertySource; 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, private PropertySource<?> getPropertySource(String name, Resource resource,
String profile, List<PropertySourceLoader> loaders) { String profile, List<PropertySourceLoader> loaders) {
String key = resource.getDescription() + (profile == null ? "" : "#" + profile); String key = resource.getDescription() + (profile == null ? "" : "#" + profile);
@ -364,25 +395,33 @@ public class ConfigFileApplicationContextInitializer implements
private Map<String, String> names = new HashMap<String, String>(); private Map<String, String> names = new HashMap<String, String>();
private Map<String, Class<?>> configs = new HashMap<String, Class<?>>();
private Map<String, Boolean> ignores = new HashMap<String, Boolean>(); private Map<String, Boolean> ignores = new HashMap<String, Boolean>();
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)); this.locations.addAll(Arrays.asList(locations));
if (StringUtils.hasText(name)) { if (StringUtils.hasText(name)) {
for (String location : locations) { for (String location : locations) {
this.names.put(location, name); this.names.put(location, name);
} }
for (String location : locations) { }
boolean reallyIgnore = ignoreResourceNotFound; for (String location : locations) {
if (this.ignores.containsKey(location)) { boolean reallyIgnore = ignoreResourceNotFound;
// Only if they all ignore this location will it be ignored if (this.ignores.containsKey(location)) {
reallyIgnore &= this.ignores.get(location); // Only if they all ignore this location will it be ignored
} reallyIgnore &= this.ignores.get(location);
this.ignores.put(location, reallyIgnore);
} }
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) { public boolean ignoreResourceNotFound(String location) {
return this.ignores.containsKey(location) ? this.ignores.get(location) return this.ignores.containsKey(location) ? this.ignores.get(location)
: false; : false;

@ -24,6 +24,7 @@ import org.junit.Test;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource; import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.StaticApplicationContext; import org.springframework.context.support.StaticApplicationContext;
import org.springframework.core.env.MapPropertySource; 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.notNullValue;
import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.nullValue;
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat; import static org.junit.Assert.assertThat;
/** /**
@ -196,6 +198,35 @@ public class ConfigFileApplicationContextInitializerTests {
context.close(); 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 @Test
public void propertySourceAnnotationMultipleLocations() throws Exception { public void propertySourceAnnotationMultipleLocations() throws Exception {
SpringApplication application = new SpringApplication( 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 @Configuration
@PropertySource({ "classpath:/specificlocation.properties", @PropertySource({ "classpath:/specificlocation.properties",
"classpath:/moreproperties.properties" }) "classpath:/moreproperties.properties" })

Loading…
Cancel
Save