mirror of
https://github.com/spring-projects/spring-boot.git
synced 2024-07-05 00:56:58 +08:00
[bs-168] Support convenient binding of @Bean to external source
@ConfigurationProperties now has a path() attribute that can be used to specify a resource location explicitly. [Fixes #51968657]
This commit is contained in:
parent
15ba11f302
commit
d5aad97d1f
@ -38,8 +38,9 @@ import org.springframework.validation.ObjectError;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
/**
|
||||
* Validate some {@link Properties} by binding them to an object of a specified type and
|
||||
* then optionally running a {@link Validator} over it.
|
||||
* Validate some {@link Properties} (or optionally {@link PropertySources}) by binding
|
||||
* them to an object of a specified type and then optionally running a {@link Validator}
|
||||
* over it.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
@ -195,15 +196,13 @@ public class PropertiesConfigurationFactory<T> implements FactoryBean<T>,
|
||||
if (this.logger.isTraceEnabled()) {
|
||||
if (this.properties != null) {
|
||||
this.logger.trace("Properties:\n" + this.properties);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
this.logger.trace("Property Sources: " + this.propertySources);
|
||||
}
|
||||
}
|
||||
this.hasBeenBound = true;
|
||||
doBindPropertiesToTarget();
|
||||
}
|
||||
catch (BindException ex) {
|
||||
} catch (BindException ex) {
|
||||
if (this.exceptionIfInvalid) {
|
||||
throw ex;
|
||||
}
|
||||
|
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
||||
import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
||||
|
||||
/**
|
||||
* A {@link DocumentMatcher} that matches the default profile implicitly but not
|
||||
* explicitly (i.e. matches if "spring.profiles" is not found and not otherwise).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public final class DefaultProfileDocumentMatcher implements DocumentMatcher {
|
||||
|
||||
@Override
|
||||
public MatchStatus matches(Properties properties) {
|
||||
if (!properties.containsKey("spring.profiles")) {
|
||||
return MatchStatus.FOUND;
|
||||
} else {
|
||||
return MatchStatus.NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
|
||||
/**
|
||||
* Strategy to load '.properties' files into a {@link PropertySource}.
|
||||
*/
|
||||
public class PropertiesPropertySourceLoader implements PropertySourceLoader {
|
||||
|
||||
@Override
|
||||
public boolean supports(Resource resource) {
|
||||
return resource.getFilename().endsWith(".properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PropertySource<?> load(Resource resource, Environment environment) {
|
||||
try {
|
||||
Properties properties = loadProperties(resource, environment);
|
||||
return new PropertiesPropertySource(resource.getDescription(), properties);
|
||||
} catch (IOException ex) {
|
||||
throw new IllegalStateException("Could not load properties from " + resource,
|
||||
ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected Properties loadProperties(Resource resource, Environment environment)
|
||||
throws IOException {
|
||||
return PropertiesLoaderUtils.loadProperties(resource);
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.config;
|
||||
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Strategy interface used to load a {@link PropertySource}.
|
||||
*/
|
||||
public interface PropertySourceLoader {
|
||||
|
||||
/**
|
||||
* @return Is this resource supported?
|
||||
*/
|
||||
public boolean supports(Resource resource);
|
||||
|
||||
/**
|
||||
* Load the resource into a property source.
|
||||
* @return a property source
|
||||
*/
|
||||
PropertySource<?> load(Resource resource, Environment environment);
|
||||
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.config;
|
||||
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.bootstrap.config.YamlProcessor.ArrayDocumentMatcher;
|
||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
||||
import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
||||
import org.springframework.core.env.Environment;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class SpringProfileDocumentMatcher implements DocumentMatcher {
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
/**
|
||||
* @param environment
|
||||
*/
|
||||
public SpringProfileDocumentMatcher(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchStatus matches(Properties properties) {
|
||||
String[] profiles = this.environment.getActiveProfiles();
|
||||
if (profiles.length == 0) {
|
||||
profiles = new String[] { "default" };
|
||||
}
|
||||
return new ArrayDocumentMatcher("spring.profiles", profiles).matches(properties);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,81 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.config;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
/**
|
||||
* Strategy to load '.yml' files into a {@link PropertySource}.
|
||||
*/
|
||||
public class YamlPropertySourceLoader extends PropertiesPropertySourceLoader {
|
||||
|
||||
private List<DocumentMatcher> matchers;
|
||||
|
||||
/**
|
||||
* A property source loader that loads all properties and matches all documents.
|
||||
*
|
||||
* @return a property source loader
|
||||
*/
|
||||
public static YamlPropertySourceLoader matchAllLoader() {
|
||||
return new YamlPropertySourceLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* A property source loader that matches documents that have no explicit profile or
|
||||
* which have an explicit "spring.profiles.active" value in the current active
|
||||
* profiles.
|
||||
*
|
||||
* @return a property source loader
|
||||
*/
|
||||
public static YamlPropertySourceLoader springProfileAwareLoader(
|
||||
Environment environment) {
|
||||
return new YamlPropertySourceLoader(new SpringProfileDocumentMatcher(environment),
|
||||
new DefaultProfileDocumentMatcher());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param matchers
|
||||
*/
|
||||
public YamlPropertySourceLoader(DocumentMatcher... matchers) {
|
||||
this.matchers = Arrays.asList(matchers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supports(Resource resource) {
|
||||
return resource.getFilename().endsWith(".yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties loadProperties(final Resource resource,
|
||||
final Environment environment) throws IOException {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
if (this.matchers != null && !this.matchers.isEmpty()) {
|
||||
factory.setMatchDefault(false);
|
||||
factory.setDocumentMatchers(this.matchers);
|
||||
}
|
||||
factory.setResources(new Resource[] { resource });
|
||||
return factory.getObject();
|
||||
}
|
||||
|
||||
}
|
@ -16,26 +16,21 @@
|
||||
|
||||
package org.springframework.bootstrap.context.initializer;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.bootstrap.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.bootstrap.config.YamlProcessor.ArrayDocumentMatcher;
|
||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
||||
import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
||||
import org.springframework.bootstrap.config.SpringProfileDocumentMatcher;
|
||||
import org.springframework.bootstrap.config.PropertiesPropertySourceLoader;
|
||||
import org.springframework.bootstrap.config.PropertySourceLoader;
|
||||
import org.springframework.bootstrap.config.YamlPropertySourceLoader;
|
||||
import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.annotation.PropertySource;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.env.CommandLinePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertiesPropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@ -69,8 +64,6 @@ import org.springframework.util.StringUtils;
|
||||
public class ConfigFileApplicationContextInitializer implements
|
||||
ApplicationContextInitializer<ConfigurableApplicationContext>, Ordered {
|
||||
|
||||
private static final Loader[] LOADERS = { new PropertiesLoader(), new YamlLoader() };
|
||||
|
||||
private static final String LOCATION_VARIABLE = "${spring.config.location}";
|
||||
|
||||
private String[] searchLocations = new String[] { "classpath:", "file:./",
|
||||
@ -100,11 +93,9 @@ public class ConfigFileApplicationContextInitializer implements
|
||||
private List<String> getCandidateLocations() {
|
||||
List<String> candidates = new ArrayList<String>();
|
||||
for (String searchLocation : this.searchLocations) {
|
||||
for (Loader loader : LOADERS) {
|
||||
for (String extension : loader.getExtensions()) {
|
||||
String location = searchLocation + this.name + extension;
|
||||
candidates.add(location);
|
||||
}
|
||||
for (String extension : new String[] { ".properties", ".yml" }) {
|
||||
String location = searchLocation + this.name + extension;
|
||||
candidates.add(location);
|
||||
}
|
||||
}
|
||||
candidates.add(LOCATION_VARIABLE);
|
||||
@ -113,16 +104,30 @@ public class ConfigFileApplicationContextInitializer implements
|
||||
|
||||
private void load(ConfigurableApplicationContext applicationContext, String location,
|
||||
String profile) {
|
||||
location = applicationContext.getEnvironment().resolvePlaceholders(location);
|
||||
|
||||
ConfigurableEnvironment environment = applicationContext.getEnvironment();
|
||||
location = environment.resolvePlaceholders(location);
|
||||
String suffix = "." + StringUtils.getFilenameExtension(location);
|
||||
if (StringUtils.hasLength(profile)) {
|
||||
location = location.replace(suffix, "-" + profile + suffix);
|
||||
}
|
||||
for (Loader loader : LOADERS) {
|
||||
if (loader.getExtensions().contains(suffix.toLowerCase())) {
|
||||
Resource resource = applicationContext.getResource(location);
|
||||
if (resource != null && resource.exists()) {
|
||||
loader.load(resource, applicationContext);
|
||||
PropertySourceLoader[] loaders = {
|
||||
new PropertiesPropertySourceLoader(),
|
||||
new YamlPropertySourceLoader(new SpringProfileDocumentMatcher(environment),
|
||||
new ProfileSettingDocumentMatcher(environment)) };
|
||||
for (PropertySourceLoader loader : loaders) {
|
||||
Resource resource = applicationContext.getResource(location);
|
||||
if (resource != null && resource.exists() && loader.supports(resource)) {
|
||||
PropertySource<?> propertySource = loader.load(resource, environment);
|
||||
MutablePropertySources propertySources = environment.getPropertySources();
|
||||
if (propertySources
|
||||
.contains(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
|
||||
propertySources.addAfter(
|
||||
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
|
||||
propertySource);
|
||||
|
||||
} else {
|
||||
propertySources.addFirst(propertySource);
|
||||
}
|
||||
return;
|
||||
}
|
||||
@ -152,118 +157,4 @@ public class ConfigFileApplicationContextInitializer implements
|
||||
this.searchLocations = (searchLocations == null ? null : searchLocations.clone());
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy interface used to load a {@link PropertySource}.
|
||||
*/
|
||||
private static interface Loader {
|
||||
|
||||
/**
|
||||
* @return The supported extensions (including '.' and in lowercase)
|
||||
*/
|
||||
public Set<String> getExtensions();
|
||||
|
||||
/**
|
||||
* Load the resource into the destination application context.
|
||||
*/
|
||||
void load(Resource resource, ConfigurableApplicationContext applicationContext);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy to load '.properties' files.
|
||||
*/
|
||||
private static class PropertiesLoader implements Loader {
|
||||
|
||||
@Override
|
||||
public Set<String> getExtensions() {
|
||||
return Collections.singleton(".properties");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load(Resource resource,
|
||||
ConfigurableApplicationContext applicationContext) {
|
||||
try {
|
||||
Properties properties = loadProperties(resource, applicationContext);
|
||||
MutablePropertySources propertySources = applicationContext
|
||||
.getEnvironment().getPropertySources();
|
||||
if (propertySources
|
||||
.contains(CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME)) {
|
||||
propertySources.addAfter(
|
||||
CommandLinePropertySource.COMMAND_LINE_PROPERTY_SOURCE_NAME,
|
||||
new PropertiesPropertySource(resource.getDescription(),
|
||||
properties));
|
||||
|
||||
}
|
||||
else {
|
||||
propertySources.addFirst(new PropertiesPropertySource(resource
|
||||
.getDescription(), properties));
|
||||
}
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new IllegalStateException("Could not load properties file from "
|
||||
+ resource, ex);
|
||||
}
|
||||
}
|
||||
|
||||
protected Properties loadProperties(Resource resource,
|
||||
ConfigurableApplicationContext applicationContext) throws IOException {
|
||||
return PropertiesLoaderUtils.loadProperties(resource);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy to load '.yml' files.
|
||||
*/
|
||||
private static class YamlLoader extends PropertiesLoader {
|
||||
|
||||
@Override
|
||||
public Set<String> getExtensions() {
|
||||
return Collections.singleton(".yml");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Properties loadProperties(final Resource resource,
|
||||
final ConfigurableApplicationContext applicationContext)
|
||||
throws IOException {
|
||||
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
|
||||
List<DocumentMatcher> matchers = new ArrayList<DocumentMatcher>();
|
||||
matchers.add(new DocumentMatcher() {
|
||||
@Override
|
||||
public MatchStatus matches(Properties properties) {
|
||||
String[] profiles = applicationContext.getEnvironment()
|
||||
.getActiveProfiles();
|
||||
if (profiles.length == 0) {
|
||||
profiles = new String[] { "default" };
|
||||
}
|
||||
return new ArrayDocumentMatcher("spring.profiles", profiles)
|
||||
.matches(properties);
|
||||
|
||||
}
|
||||
});
|
||||
matchers.add(new DocumentMatcher() {
|
||||
@Override
|
||||
public MatchStatus matches(Properties properties) {
|
||||
if (!properties.containsKey("spring.profiles")) {
|
||||
Set<String> profiles = StringUtils
|
||||
.commaDelimitedListToSet(properties.getProperty(
|
||||
"spring.profiles.active", ""));
|
||||
for (String profile : profiles) {
|
||||
// allow document with no profile to set the active one
|
||||
applicationContext.getEnvironment().addActiveProfile(profile);
|
||||
}
|
||||
// matches default profile
|
||||
return MatchStatus.FOUND;
|
||||
}
|
||||
else {
|
||||
return MatchStatus.NOT_FOUND;
|
||||
}
|
||||
}
|
||||
});
|
||||
factory.setMatchDefault(false);
|
||||
factory.setDocumentMatchers(matchers);
|
||||
factory.setResources(new Resource[] { resource });
|
||||
return factory.getObject();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright 2012-2013 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.bootstrap.context.initializer;
|
||||
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.bootstrap.config.YamlProcessor.DocumentMatcher;
|
||||
import org.springframework.bootstrap.config.YamlProcessor.MatchStatus;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* A {@link DocumentMatcher} that sets the active profile if it finds a document with
|
||||
* a key <code>spring.profiles.active</code>.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public final class ProfileSettingDocumentMatcher implements DocumentMatcher {
|
||||
|
||||
private final Environment environment;
|
||||
|
||||
public ProfileSettingDocumentMatcher(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MatchStatus matches(Properties properties) {
|
||||
if (!properties.containsKey("spring.profiles")) {
|
||||
Set<String> profiles = StringUtils.commaDelimitedListToSet(properties
|
||||
.getProperty("spring.profiles.active", ""));
|
||||
if (this.environment instanceof ConfigurableEnvironment) {
|
||||
ConfigurableEnvironment configurable = (ConfigurableEnvironment) this.environment;
|
||||
for (String profile : profiles) {
|
||||
// allow document with no profile to set the active one
|
||||
configurable.addActiveProfile(profile);
|
||||
}
|
||||
}
|
||||
// matches default profile
|
||||
return MatchStatus.FOUND;
|
||||
} else {
|
||||
return MatchStatus.NOT_FOUND;
|
||||
}
|
||||
}
|
||||
}
|
@ -70,4 +70,12 @@ public @interface ConfigurationProperties {
|
||||
*/
|
||||
boolean ignoreUnknownFields() default true;
|
||||
|
||||
/**
|
||||
* Optionally provide an explicit resource path to bind to instead of using the
|
||||
* default environment.
|
||||
*
|
||||
* @return the path (or paths) of resources to bind to
|
||||
*/
|
||||
String[] path() default {};
|
||||
|
||||
}
|
||||
|
@ -23,11 +23,23 @@ import org.springframework.beans.factory.BeanFactoryAware;
|
||||
import org.springframework.beans.factory.ListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.bootstrap.bind.PropertiesConfigurationFactory;
|
||||
import org.springframework.bootstrap.config.PropertiesPropertySourceLoader;
|
||||
import org.springframework.bootstrap.config.PropertySourceLoader;
|
||||
import org.springframework.bootstrap.config.YamlPropertySourceLoader;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
import org.springframework.context.ResourceLoaderAware;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.convert.ConversionService;
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.core.convert.support.DefaultConversionService;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.env.MutablePropertySources;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
import org.springframework.core.env.PropertySources;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.Validator;
|
||||
|
||||
@ -38,7 +50,7 @@ import org.springframework.validation.Validator;
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor,
|
||||
BeanFactoryAware {
|
||||
BeanFactoryAware, ResourceLoaderAware, EnvironmentAware {
|
||||
|
||||
private PropertySources propertySources;
|
||||
|
||||
@ -52,6 +64,10 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
private ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
|
||||
private Environment environment = new StandardEnvironment();
|
||||
|
||||
/**
|
||||
* @param propertySources
|
||||
*/
|
||||
@ -78,6 +94,16 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||
this.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResourceLoader(ResourceLoader resourceLoader) {
|
||||
this.resourceLoader = resourceLoader;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnvironment(Environment environment) {
|
||||
this.environment = environment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
@ -101,7 +127,12 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||
.getTarget() : bean);
|
||||
PropertiesConfigurationFactory<Object> factory = new PropertiesConfigurationFactory<Object>(
|
||||
target);
|
||||
factory.setPropertySources(this.propertySources);
|
||||
if (annotation != null && annotation.path().length != 0) {
|
||||
|
||||
factory.setPropertySources(loadPropertySources(annotation.path()));
|
||||
} else {
|
||||
factory.setPropertySources(this.propertySources);
|
||||
}
|
||||
factory.setValidator(this.validator);
|
||||
// If no explicit conversion service is provided we add one so that (at least)
|
||||
// comma-separated arrays of convertibles can be bound automatically
|
||||
@ -118,12 +149,31 @@ public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProc
|
||||
}
|
||||
try {
|
||||
factory.bindPropertiesToTarget();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
} catch (Exception ex) {
|
||||
throw new BeanCreationException(beanName, "Could not bind properties", ex);
|
||||
}
|
||||
}
|
||||
|
||||
private PropertySources loadPropertySources(String[] path) {
|
||||
MutablePropertySources propertySources = new MutablePropertySources();
|
||||
PropertySourceLoader[] loaders = { new PropertiesPropertySourceLoader(),
|
||||
YamlPropertySourceLoader.springProfileAwareLoader(this.environment) };
|
||||
for (String location : path) {
|
||||
location = this.environment.resolvePlaceholders(location);
|
||||
Resource resource = this.resourceLoader.getResource(location);
|
||||
if (resource != null && resource.exists()) {
|
||||
for (PropertySourceLoader loader : loaders) {
|
||||
if (loader.supports(resource)) {
|
||||
PropertySource<?> propertySource = loader.load(resource,
|
||||
this.environment);
|
||||
propertySources.addFirst(propertySource);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return propertySources;
|
||||
}
|
||||
|
||||
private ConversionService getDefaultConversionService() {
|
||||
if (!this.initialized && this.beanFactory instanceof ListableBeanFactory) {
|
||||
for (Converter<?, ?> converter : ((ListableBeanFactory) this.beanFactory)
|
||||
|
@ -120,6 +120,49 @@ public class EnableConfigurationPropertiesTests {
|
||||
assertEquals("bar", this.context.getBean(TestProperties.class).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingDirectlyToFile() {
|
||||
this.context.register(ResourceBindingProperties.class, TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertEquals(1,
|
||||
this.context.getBeanNamesForType(ResourceBindingProperties.class).length);
|
||||
assertEquals("foo", this.context.getBean(ResourceBindingProperties.class)
|
||||
.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingDirectlyToFileResolvedFromEnvironment() {
|
||||
TestUtils.addEnviroment(this.context, "binding.location:classpath:other.yml");
|
||||
this.context.register(ResourceBindingProperties.class, TestConfiguration.class);
|
||||
this.context.refresh();
|
||||
assertEquals(1,
|
||||
this.context.getBeanNamesForType(ResourceBindingProperties.class).length);
|
||||
assertEquals("other", this.context.getBean(ResourceBindingProperties.class)
|
||||
.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingDirectlyToFileWithDefaultsWhenProfileNotFound() {
|
||||
this.context.register(ResourceBindingProperties.class, TestConfiguration.class);
|
||||
this.context.getEnvironment().addActiveProfile("nonexistent");
|
||||
this.context.refresh();
|
||||
assertEquals(1,
|
||||
this.context.getBeanNamesForType(ResourceBindingProperties.class).length);
|
||||
assertEquals("foo", this.context.getBean(ResourceBindingProperties.class)
|
||||
.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingDirectlyToFileWithExplicitSpringProfile() {
|
||||
this.context.register(ResourceBindingProperties.class, TestConfiguration.class);
|
||||
this.context.getEnvironment().addActiveProfile("super");
|
||||
this.context.refresh();
|
||||
assertEquals(1,
|
||||
this.context.getBeanNamesForType(ResourceBindingProperties.class).length);
|
||||
assertEquals("bar", this.context.getBean(ResourceBindingProperties.class)
|
||||
.getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBindingWithTwoBeans() {
|
||||
this.context.register(MoreConfiguration.class, TestConfiguration.class);
|
||||
@ -246,4 +289,16 @@ public class EnableConfigurationPropertiesTests {
|
||||
}
|
||||
}
|
||||
|
||||
@ConfigurationProperties(path = "${binding.location:classpath:name.yml}")
|
||||
protected static class ResourceBindingProperties {
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
10
spring-bootstrap/src/test/resources/name.yml
Normal file
10
spring-bootstrap/src/test/resources/name.yml
Normal file
@ -0,0 +1,10 @@
|
||||
---
|
||||
name: foo
|
||||
|
||||
---
|
||||
spring.profiles: super
|
||||
name: bar
|
||||
|
||||
---
|
||||
spring.profiles: other
|
||||
name: spam
|
2
spring-bootstrap/src/test/resources/other.yml
Normal file
2
spring-bootstrap/src/test/resources/other.yml
Normal file
@ -0,0 +1,2 @@
|
||||
---
|
||||
name: other
|
Loading…
Reference in New Issue
Block a user