Browse Source

Refine ConfigFileApplicationListener a little

pull/272/head
Phillip Webb 12 years ago
parent
commit
a77034bff0
  1. 45
      spring-boot/src/main/java/org/springframework/boot/config/DefaultPropertySourceLoadersFactory.java
  2. 39
      spring-boot/src/main/java/org/springframework/boot/config/PropertySourceLoadersFactory.java
  3. 394
      spring-boot/src/main/java/org/springframework/boot/context/listener/ConfigFileApplicationListener.java
  4. 4
      spring-boot/src/test/java/org/springframework/boot/context/listener/ConfigFileApplicationListenerTests.java

45
spring-boot/src/main/java/org/springframework/boot/config/DefaultPropertySourceLoadersFactory.java

@ -0,0 +1,45 @@
/*
* Copyright 2012-2014 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.config;
import java.util.ArrayList;
import java.util.List;
import org.springframework.core.env.Environment;
import org.springframework.util.ClassUtils;
/**
* Default implementation of {@link PropertySourceLoadersFactory}. Provides a
* {@link PropertiesPropertySourceLoader} and when possible a
* {@link YamlPropertySourceLoader}.
*
* @author Dave Syer
*/
public class DefaultPropertySourceLoadersFactory implements PropertySourceLoadersFactory {
@Override
public List<PropertySourceLoader> getLoaders(Environment environment) {
ArrayList<PropertySourceLoader> loaders = new ArrayList<PropertySourceLoader>();
loaders.add(new PropertiesPropertySourceLoader());
if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
loaders.add(YamlPropertySourceLoader.springProfileAwareLoader(environment
.getActiveProfiles()));
}
return loaders;
}
}

39
spring-boot/src/main/java/org/springframework/boot/config/PropertySourceLoadersFactory.java

@ -0,0 +1,39 @@
/*
* Copyright 2012-2014 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.config;
import java.util.List;
import org.springframework.core.env.Environment;
/**
* Factory to return {@link PropertySourceLoader}s.
*
* @author Dave Syer
* @see DefaultPropertySourceLoadersFactory
*/
public interface PropertySourceLoadersFactory {
/**
* Return a list of {@link PropertySourceLoader}s in the order that they should be
* tried.
* @param environment the source environment
* @return a list of loaders
*/
List<PropertySourceLoader> getLoaders(Environment environment);
}

394
spring-boot/src/main/java/org/springframework/boot/context/listener/ConfigFileApplicationListener.java

@ -21,6 +21,7 @@ import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet; import java.util.LinkedHashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -33,26 +34,24 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationEnvironmentAvailableEvent; import org.springframework.boot.SpringApplicationEnvironmentAvailableEvent;
import org.springframework.boot.bind.PropertySourcesPropertyValues; import org.springframework.boot.bind.PropertySourcesPropertyValues;
import org.springframework.boot.bind.RelaxedDataBinder; import org.springframework.boot.bind.RelaxedDataBinder;
import org.springframework.boot.config.PropertiesPropertySourceLoader; import org.springframework.boot.config.DefaultPropertySourceLoadersFactory;
import org.springframework.boot.config.PropertySourceLoader; import org.springframework.boot.config.PropertySourceLoader;
import org.springframework.boot.config.YamlPropertySourceLoader; import org.springframework.boot.config.PropertySourceLoadersFactory;
import org.springframework.context.ApplicationListener; import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.AnnotatedBeanDefinitionReader; 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.AnnotationUtils;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService; import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource; import org.springframework.core.env.PropertySource;
import org.springframework.core.env.StandardEnvironment; import org.springframework.core.env.StandardEnvironment;
import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource; import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader; import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.core.type.StandardAnnotationMetadata;
import org.springframework.util.ClassUtils;
import org.springframework.util.DigestUtils; import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
@ -66,16 +65,13 @@ import org.springframework.util.StringUtils;
* <li>classpath:config/</li> * <li>classpath:config/</li>
* <li>file:./config/:</li> * <li>file:./config/:</li>
* </ul> * </ul>
*
* <p> * <p>
* Alternative locations and names can be specified using * Alternative locations and names can be specified using
* {@link #setSearchLocations(String[])} and {@link #setNames(String)}. * {@link #setSearchLocations(String[])} and {@link #setNames(String)}.
*
* <p> * <p>
* Additional files will also be loaded based on active profiles. For example if a 'web' * Additional files will also be loaded based on active profiles. For example if a 'web'
* profile is active 'application-web.properties' and 'application-web.yml' will be * profile is active 'application-web.properties' and 'application-web.yml' will be
* considered. * considered.
*
* <p> * <p>
* The 'spring.config.name' property can be used to specify an alternative name to load or * The 'spring.config.name' property can be used to specify an alternative name to load or
* alternatively the 'spring.config.location' property can be used to specify an exact * alternatively the 'spring.config.location' property can be used to specify an exact
@ -87,6 +83,8 @@ import org.springframework.util.StringUtils;
public class ConfigFileApplicationListener implements public class ConfigFileApplicationListener implements
ApplicationListener<SpringApplicationEnvironmentAvailableEvent>, Ordered { ApplicationListener<SpringApplicationEnvironmentAvailableEvent>, Ordered {
private static final String ACTIVE_PROFILES_PROPERTY = "spring.profiles.active";
private static final String LOCATION_VARIABLE = "${spring.config.location}"; private static final String LOCATION_VARIABLE = "${spring.config.location}";
private String[] searchLocations = new String[] { "classpath:", "file:./", private String[] searchLocations = new String[] { "classpath:", "file:./",
@ -96,13 +94,13 @@ public class ConfigFileApplicationListener implements
private int order = Integer.MIN_VALUE + 10; private int order = Integer.MIN_VALUE + 10;
private final Map<String, PropertySource<?>> cached = new HashMap<String, PropertySource<?>>();
private final ConversionService conversionService = new DefaultConversionService(); private final ConversionService conversionService = new DefaultConversionService();
private final PropertySourceAnnotations propertySourceAnnotations = new PropertySourceAnnotations(); private final Map<String, PropertySource<?>> cache = new HashMap<String, PropertySource<?>>();
private final PropertySourceAnnotations annotations = new PropertySourceAnnotations();
private PropertySourceLoaderFactory propertySourceLoaderFactory = new DefaultPropertySourceLoaderFactory(); private PropertySourceLoadersFactory propertySourceLoadersFactory = new DefaultPropertySourceLoadersFactory();
/** /**
* Binds the early {@link Environment} to the {@link SpringApplication}. This makes it * Binds the early {@link Environment} to the {@link SpringApplication}. This makes it
@ -113,81 +111,63 @@ public class ConfigFileApplicationListener implements
*/ */
@Override @Override
public void onApplicationEvent(SpringApplicationEnvironmentAvailableEvent event) { public void onApplicationEvent(SpringApplicationEnvironmentAvailableEvent event) {
Environment created = event.getEnvironment(); Environment environment = event.getEnvironment();
if (created instanceof ConfigurableEnvironment) { if (environment instanceof ConfigurableEnvironment) {
SpringApplication springApplication = event.getSpringApplication(); configure((ConfigurableEnvironment) environment, event.getSpringApplication());
extractPropertySources(springApplication.getSources());
ConfigurableEnvironment environment = (ConfigurableEnvironment) created;
load(environment, new DefaultResourceLoader());
environment.getPropertySources().addAfter(
StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
new RandomValuePropertySource("random"));
int before = springApplication.getSources().size();
// Set bean properties from the early environment
PropertyValues propertyValues = new PropertySourcesPropertyValues(
environment.getPropertySources());
RelaxedDataBinder binder = new RelaxedDataBinder(springApplication,
"spring.main");
binder.setConversionService(this.conversionService);
binder.bind(propertyValues);
int after = springApplication.getSources().size();
if (after > before) {
// Do it again in case there are new @PropertySources
onApplicationEvent(event);
}
} }
} }
private void extractPropertySources(Set<Object> sources) { private void configure(ConfigurableEnvironment environment,
for (Object source : sources) { SpringApplication springApplication) {
if (source instanceof Class) { for (Object source : springApplication.getSources()) {
Class<?> type = (Class<?>) source; this.annotations.addFromSource(source);
for (AnnotationAttributes propertySource : attributesForRepeatable( }
new StandardAnnotationMetadata(type), PropertySources.class, load(environment, new DefaultResourceLoader());
org.springframework.context.annotation.PropertySource.class)) { environment.getPropertySources().addAfter(
this.propertySourceAnnotations.add(type, StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME,
propertySource.getStringArray("value"), new RandomValuePropertySource("random"));
propertySource.getBoolean("ignoreResourceNotFound"),
propertySource.getString("name")); int sourcesSizeBefore = springApplication.getSources().size();
} // Set bean properties from the early environment
} PropertyValues propertyValues = new PropertySourcesPropertyValues(
environment.getPropertySources());
RelaxedDataBinder binder = new RelaxedDataBinder(springApplication, "spring.main");
binder.setConversionService(this.conversionService);
binder.bind(propertyValues);
if (springApplication.getSources().size() > sourcesSizeBefore) {
// Configure again in case there are new @PropertySources
configure(environment, springApplication);
} }
} }
@SuppressWarnings("unchecked") private void load(ConfigurableEnvironment environment, ResourceLoader resourceLoader) {
static Set<AnnotationAttributes> attributesForRepeatable(AnnotationMetadata metadata,
Class<?> containerClass, Class<?> annotationClass) { LoadCandidates candidates = new LoadCandidates(environment, resourceLoader);
Set<AnnotationAttributes> result = new LinkedHashSet<AnnotationAttributes>(); PropertySource<?> defaultProperties = environment.getPropertySources().remove(
"defaultProperties");
addAttributesIfNotNull(result, String firstPropertySourceName = loadInitial(environment, resourceLoader,
metadata.getAnnotationAttributes(annotationClass.getName(), false)); candidates);
Map<String, Object> container = metadata.getAnnotationAttributes( if (environment.containsProperty(ACTIVE_PROFILES_PROPERTY)) {
containerClass.getName(), false); for (String activeProfile : StringUtils.commaDelimitedListToSet(environment
if (container != null && container.containsKey("value")) { .getProperty(ACTIVE_PROFILES_PROPERTY).toString())) {
for (Map<String, Object> containedAttributes : (Map<String, Object>[]) container environment.addActiveProfile(activeProfile);
.get("value")) {
addAttributesIfNotNull(result, containedAttributes);
} }
} }
return Collections.unmodifiableSet(result);
}
private static void addAttributesIfNotNull(Set<AnnotationAttributes> result, // Second load for specific profiles
Map<String, Object> attributes) { loadAgain(environment, resourceLoader, candidates, firstPropertySourceName);
if (attributes != null) {
result.add(AnnotationAttributes.fromMap(attributes)); if (defaultProperties != null) {
environment.getPropertySources().addLast(defaultProperties);
} }
} }
private void load(ConfigurableEnvironment environment, ResourceLoader resourceLoader) { private String loadInitial(ConfigurableEnvironment environment,
ResourceLoader resourceLoader, LoadCandidates candidates) {
List<String> candidates = getCandidateLocations(environment, resourceLoader); String firstSourceName = null;
Collections.reverse(candidates);
PropertySource<?> removed = environment.getPropertySources().remove(
"defaultProperties");
String first = null;
// Initial load allows profiles to be activated // Initial load allows profiles to be activated
for (String candidate : candidates) { for (String candidate : candidates) {
for (String path : StringUtils.commaDelimitedListToStringArray(environment for (String path : StringUtils.commaDelimitedListToStringArray(environment
@ -200,87 +180,51 @@ public class ConfigFileApplicationListener implements
path = StringUtils.cleanPath(path); path = StringUtils.cleanPath(path);
} }
PropertySource<?> source = load(environment, resourceLoader, path, null); PropertySource<?> source = loadPropertySource(environment,
resourceLoader, path, null);
if (source != null) { if (source != null) {
if (first == null) { if (firstSourceName == null) {
first = source.getName(); firstSourceName = source.getName();
} }
environment.getPropertySources().addLast(source); environment.getPropertySources().addLast(source);
} }
}
}
if (environment.containsProperty("spring.profiles.active")) {
Set<String> profiles = StringUtils.commaDelimitedListToSet(environment
.getProperty("spring.profiles.active").toString());
for (String active : profiles) {
// allow document with no profile to set the active one
environment.addActiveProfile(active);
} }
} }
return firstSourceName;
}
// Second load for specific profiles private void loadAgain(ConfigurableEnvironment environment,
ResourceLoader resourceLoader, LoadCandidates candidates,
String firstPropertySourceName) {
for (String profile : environment.getActiveProfiles()) { for (String profile : environment.getActiveProfiles()) {
for (String candidate : candidates) { for (String candidate : candidates) {
PropertySource<?> source = load(environment, resourceLoader, candidate, PropertySource<?> source = loadPropertySource(environment,
profile); resourceLoader, candidate, profile);
if (source != null) { addBeforeOrLast(environment, firstPropertySourceName, source);
if (first != null) {
// Originals go at the end so they don't override the specific
// profiles
environment.getPropertySources().addBefore(first, source);
}
else {
environment.getPropertySources().addLast(source);
}
}
} }
} }
if (removed != null) {
environment.getPropertySources().addLast(removed);
}
} }
private List<String> getCandidateLocations(ConfigurableEnvironment environment, private void addBeforeOrLast(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) { String relativePropertySourceName, PropertySource<?> source) {
Set<String> candidates = new LinkedHashSet<String>(); if (source != null) {
for (String searchLocation : this.searchLocations) { MutablePropertySources propertySources = environment.getPropertySources();
for (String extension : new String[] { ".properties", ".yml" }) { // Originals go at the end so they don't override the specific profiles
for (String name : StringUtils if (relativePropertySourceName != null) {
.commaDelimitedListToStringArray(environment propertySources.addBefore(relativePropertySourceName, source);
.resolvePlaceholders(this.names))) {
String location = searchLocation + name + extension;
candidates.add(location);
}
} }
} else {
candidates.add(LOCATION_VARIABLE); propertySources.addLast(source);
/*
* @PropertySource annotation locations go last here (eventually highest
* priority). This unfortunately isn't the same semantics as @PropertySource in
* Spring and it's hard to change that (so the property source gets added again in
* last position by Spring later in the cycle).
*/
for (String location : this.propertySourceAnnotations.locations()) {
Resource resource = resourceLoader.getResource(location);
if (!this.propertySourceAnnotations.ignoreResourceNotFound(location)
&& !resource.exists()) {
throw new IllegalStateException("Resource not found: " + location);
} }
candidates.add(location);
} }
return new ArrayList<String>(candidates);
} }
private PropertySource<?> load(ConfigurableEnvironment environment, private PropertySource<?> loadPropertySource(ConfigurableEnvironment environment,
ResourceLoader resourceLoader, String location, String profile) { ResourceLoader resourceLoader, String location, String profile) {
String suffix = "." + StringUtils.getFilenameExtension(location); Class<?> type = this.annotations.configuration(location);
Class<?> type = this.propertySourceAnnotations.configuration(location);
String suffix = "." + StringUtils.getFilenameExtension(location);
if (StringUtils.hasLength(profile)) { if (StringUtils.hasLength(profile)) {
location = location.replace(suffix, "-" + profile + suffix); location = location.replace(suffix, "-" + profile + suffix);
} }
@ -289,71 +233,56 @@ public class ConfigFileApplicationListener implements
return null; return null;
} }
List<PropertySourceLoader> loaders = this.propertySourceLoaderFactory
.getLoaders(environment);
Resource resource = resourceLoader.getResource(location); Resource resource = resourceLoader.getResource(location);
String name = this.propertySourceAnnotations.name(location); String name = this.annotations.name(location);
if (name == null) { name = (name != null ? name : location);
name = location; return getPropertySource(environment, name, resource, profile);
}
PropertySource<?> propertySource = getPropertySource(name, resource, profile,
loaders);
if (propertySource == null) {
return null;
}
return propertySource;
} }
private boolean isPropertySourceAnnotationOnExcludedType(Environment environment, private boolean isPropertySourceAnnotationOnExcludedType(Environment environment,
String profile, Class<?> type, String location) { String profile, Class<?> type, String location) {
if (type == null) { if (type == null) {
// No configuration class to worry about, just a vanilla properties location // No configuration class to worry about, just a vanilla properties location
return false; return false;
} }
if (StringUtils.hasText(profile) if (StringUtils.hasText(profile)
&& !this.propertySourceAnnotations.locations().contains(location)) { && !this.annotations.getLocations().contains(location)) {
// We are looking for profile specific properties and this one isn't // We are looking for profile specific properties and this one isn't
// explicitly asked for in propertySourceAnnotations // explicitly asked for in propertySourceAnnotations
return true; return true;
} }
AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader( AnnotatedBeanDefinitionReader reader = new AnnotatedBeanDefinitionReader(
new DefaultListableBeanFactory(), environment); new DefaultListableBeanFactory(), environment);
int before = reader.getRegistry().getBeanDefinitionCount(); int before = reader.getRegistry().getBeanDefinitionCount();
reader.register(type); reader.register(type);
int after = reader.getRegistry().getBeanDefinitionCount(); int after = reader.getRegistry().getBeanDefinitionCount();
if (after == before) {
// The configuration class was @Conditional and excluded // Return if the configuration class was @Conditional and excluded
return true; return (after == before);
}
return false;
} }
private PropertySource<?> getPropertySource(String name, Resource resource, private PropertySource<?> getPropertySource(Environment environment, String name,
String profile, List<PropertySourceLoader> loaders) { Resource resource, String profile) {
if (resource == null || !resource.exists()) { if (resource == null || !resource.exists()) {
return null; return null;
} }
String key = resource.getDescription() + (profile == null ? "" : "#" + profile); String key = resource.getDescription() + (profile == null ? "" : "#" + profile);
if (this.cached.containsKey(key)) { if (this.cache.containsKey(key)) {
return this.cached.get(key); return this.cache.get(key);
} }
boolean satisfied = true; for (PropertySourceLoader loader : this.propertySourceLoadersFactory
for (PropertySourceLoader loader : loaders) { .getLoaders(environment)) {
if (loader.supports(resource)) { if (loader.supports(resource)) {
PropertySource<?> propertySource = loader.load(name, resource); PropertySource<?> propertySource = loader.load(name, resource);
this.cached.put(key, propertySource); this.cache.put(key, propertySource);
return propertySource; return propertySource;
} }
else {
satisfied = false;
}
} }
if (!satisfied) { throw new IllegalStateException("No supported loader found for "
throw new IllegalStateException( + "configuration resource: " + resource);
"No supported loader found for configuration resource: " + resource);
}
return null;
} }
public void setOrder(int order) { public void setOrder(int order) {
@ -381,13 +310,75 @@ public class ConfigFileApplicationListener implements
} }
/** /**
* @param propertySourceLoaderFactory the factory to set * Set the {@link PropertySourceLoadersFactory} that will be used to create
* {@link PropertySourceLoader}s.
*/
public void setPropertySourceLoadersFactory(
PropertySourceLoadersFactory propertySourceLoaderFactory) {
this.propertySourceLoadersFactory = propertySourceLoaderFactory;
}
/**
* Provides {@link Iterable} access to candidate property sources.
*/ */
public void setPropertySourceLoaderFactory( private class LoadCandidates implements Iterable<String> {
PropertySourceLoaderFactory propertySourceLoaderFactory) {
this.propertySourceLoaderFactory = propertySourceLoaderFactory; private final List<String> candidates;
public LoadCandidates(ConfigurableEnvironment environment,
ResourceLoader resourceLoader) {
Set<String> candidates = new LinkedHashSet<String>();
addLoadCandidatesFromSearchLocations(environment, candidates);
candidates.add(LOCATION_VARIABLE);
// @PropertySource annotation locations go last here (eventually highest
// priority). This unfortunately isn't the same semantics as @PropertySource
// in
// Spring and it's hard to change that (so the property source gets added
// again in
// last position by Spring later in the cycle).
addLoadCandidatesFromAnnotations(resourceLoader, candidates);
this.candidates = new ArrayList<String>(candidates);
Collections.reverse(this.candidates);
}
private void addLoadCandidatesFromSearchLocations(
ConfigurableEnvironment environment, Set<String> candidates) {
for (String location : ConfigFileApplicationListener.this.searchLocations) {
for (String extension : new String[] { ".properties", ".yml" }) {
for (String name : StringUtils
.commaDelimitedListToStringArray(environment
.resolvePlaceholders(ConfigFileApplicationListener.this.names))) {
candidates.add(location + name + extension);
}
}
}
}
private void addLoadCandidatesFromAnnotations(ResourceLoader resourceLoader,
Set<String> candidates) {
for (String location : ConfigFileApplicationListener.this.annotations
.getLocations()) {
Resource resource = resourceLoader.getResource(location);
if (!ConfigFileApplicationListener.this.annotations
.ignoreResourceNotFound(location) && !resource.exists()) {
throw new IllegalStateException("Resource not found: " + location);
}
candidates.add(location);
}
}
@Override
public Iterator<String> iterator() {
return this.candidates.iterator();
}
} }
/**
* {@link PropertySource} that returns a random value for any property that starts
* with {@literal "random."}. Return a {@code byte[]} unless the property name ends
* with {@literal ".int} or {@literal ".long"}.
*/
private static class RandomValuePropertySource extends PropertySource<Random> { private static class RandomValuePropertySource extends PropertySource<Random> {
public RandomValuePropertySource(String name) { public RandomValuePropertySource(String name) {
@ -412,6 +403,10 @@ public class ConfigFileApplicationListener implements
} }
/**
* Holds details collected from
* {@link org.springframework.context.annotation.PropertySource} annotations.
*/
private static class PropertySourceAnnotations { private static class PropertySourceAnnotations {
private final Collection<String> locations = new LinkedHashSet<String>(); private final Collection<String> locations = new LinkedHashSet<String>();
@ -422,16 +417,30 @@ public class ConfigFileApplicationListener implements
private final Map<String, Boolean> ignores = new HashMap<String, Boolean>(); private final Map<String, Boolean> ignores = new HashMap<String, Boolean>();
public void add(Class<?> source, String[] locations, public void addFromSource(Object source) {
boolean ignoreResourceNotFound, String name) { if (source instanceof Class<?>) {
this.locations.addAll(Arrays.asList(locations)); addFromSource((Class<?>) source);
if (StringUtils.hasText(name)) { }
for (String location : locations) { }
this.names.put(location, name);
private void addFromSource(Class<?> source) {
for (org.springframework.context.annotation.PropertySource propertySource : AnnotationUtils
.getRepeatableAnnotation(source, PropertySources.class,
org.springframework.context.annotation.PropertySource.class)) {
add(source, propertySource);
}
}
private void add(Class<?> source,
org.springframework.context.annotation.PropertySource annotation) {
this.locations.addAll(Arrays.asList(annotation.value()));
if (StringUtils.hasText(annotation.name())) {
for (String location : annotation.value()) {
this.names.put(location, annotation.name());
} }
} }
for (String location : locations) { for (String location : annotation.value()) {
boolean reallyIgnore = ignoreResourceNotFound; boolean reallyIgnore = annotation.ignoreResourceNotFound();
if (this.ignores.containsKey(location)) { if (this.ignores.containsKey(location)) {
// Only if they all ignore this location will it be ignored // Only if they all ignore this location will it be ignored
reallyIgnore &= this.ignores.get(location); reallyIgnore &= this.ignores.get(location);
@ -446,8 +455,7 @@ public class ConfigFileApplicationListener implements
} }
public boolean ignoreResourceNotFound(String location) { public boolean ignoreResourceNotFound(String location) {
return this.ignores.containsKey(location) ? this.ignores.get(location) return Boolean.TRUE.equals(this.ignores.get(location));
: false;
} }
public String name(String location) { public String name(String location) {
@ -459,29 +467,9 @@ public class ConfigFileApplicationListener implements
return "boot." + name; return "boot." + name;
} }
public Collection<String> locations() { public Collection<String> getLocations() {
return this.locations; return this.locations;
} }
} }
public static interface PropertySourceLoaderFactory {
List<PropertySourceLoader> getLoaders(Environment environment);
}
private static class DefaultPropertySourceLoaderFactory implements
PropertySourceLoaderFactory {
@Override
public List<PropertySourceLoader> getLoaders(Environment environment) {
ArrayList<PropertySourceLoader> loaders = new ArrayList<PropertySourceLoader>();
loaders.add(new PropertiesPropertySourceLoader());
if (ClassUtils.isPresent("org.yaml.snakeyaml.Yaml", null)) {
loaders.add(YamlPropertySourceLoader.springProfileAwareLoader(environment
.getActiveProfiles()));
}
return loaders;
}
}
} }

4
spring-boot/src/test/java/org/springframework/boot/context/listener/ConfigFileApplicationListenerTests.java

@ -26,7 +26,7 @@ import org.junit.rules.ExpectedException;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.SpringApplicationEnvironmentAvailableEvent; import org.springframework.boot.SpringApplicationEnvironmentAvailableEvent;
import org.springframework.boot.config.PropertySourceLoader; import org.springframework.boot.config.PropertySourceLoader;
import org.springframework.boot.context.listener.ConfigFileApplicationListener.PropertySourceLoaderFactory; import org.springframework.boot.config.PropertySourceLoadersFactory;
import org.springframework.boot.test.EnvironmentTestUtils; import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -228,7 +228,7 @@ public class ConfigFileApplicationListenerTests {
@Test @Test
public void unsupportedResource() throws Exception { public void unsupportedResource() throws Exception {
this.initializer this.initializer
.setPropertySourceLoaderFactory(new PropertySourceLoaderFactory() { .setPropertySourceLoadersFactory(new PropertySourceLoadersFactory() {
@Override @Override
public List<PropertySourceLoader> getLoaders(Environment environment) { public List<PropertySourceLoader> getLoaders(Environment environment) {
return Arrays return Arrays

Loading…
Cancel
Save