Introduce AbstractEnvironment#customizePropertySources

This new hook in the AbstractEnvironment lifecycle allows for more
explicit and predictable customization of property sources by
subclasses.  See Javadoc and existing implementations for detail.

Issue: SPR-8354
This commit is contained in:
Chris Beams
2011-05-20 03:50:14 +00:00
parent c4a13507f0
commit 7271ba8182
5 changed files with 134 additions and 29 deletions

View File

@@ -74,8 +74,92 @@ public abstract class AbstractEnvironment implements ConfigurableEnvironment {
private Set<String> activeProfiles = new LinkedHashSet<String>();
private Set<String> defaultProfiles = new LinkedHashSet<String>(this.getReservedDefaultProfiles());
private MutablePropertySources propertySources = new MutablePropertySources();
private ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
private final MutablePropertySources propertySources = new MutablePropertySources();
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(propertySources);
public AbstractEnvironment() {
this.customizePropertySources(propertySources);
}
/**
* Customize the set of {@link PropertySource} objects to be searched by this
* {@code Environment} during calls to {@link #getProperty(String)} and related
* methods.
*
* <p>Subclasses that override this method are encouraged to add property
* sources using {@link MutablePropertySources#addLast(PropertySource)} such that
* further subclasses may call {@code super.customizePropertySources()} with
* predictable results. For example:
* <pre class="code">
* public class Level1Environment extends AbstractEnvironment {
* &#064;Override
* protected void customizePropertySources(MutablePropertySources propertySources) {
* super.customizePropertySources(propertySources); // no-op from base class
* propertySources.addLast(new PropertySourceA(...));
* propertySources.addLast(new PropertySourceB(...));
* }
* }
*
* public class Level2Environment extends Level1Environment {
* &#064;Override
* protected void customizePropertySources(MutablePropertySources propertySources) {
* super.customizePropertySources(propertySources); // add all from superclass
* propertySources.addLast(new PropertySourceC(...));
* propertySources.addLast(new PropertySourceD(...));
* }
* }
* </pre>
* In this arrangement, properties will be resolved against sources A, B, C, D in that
* order. That is to say that property source "A" has precedence over property source
* "D". If the {@code Level2Environment} subclass wished to give property sources C
* and D higher precedence than A and B, it could simply call
* {@code super.customizePropertySources} after, rather than before adding its own:
* <pre>
* public class Level2Environment extends Level1Environment {
* &#064;Override
* protected void customizePropertySources(MutablePropertySources propertySources) {
* propertySources.addLast(new PropertySourceC(...));
* propertySources.addLast(new PropertySourceD(...));
* super.customizePropertySources(propertySources); // add all from superclass
* }
* }
* </pre>
* The search order is now C, D, A, B as desired.
*
* <p>Beyond these recommendations, subclasses may use any of the <code>add&#42;</code>,
* {@code remove}, or {@code replace} methods exposed by {@link MutablePropertySources}
* in order to create the exact arrangement of property sources desired.
*
* <p>The base implementation in {@link AbstractEnvironment#customizePropertySources}
* registers no property sources.
*
* <p>Note that clients of any {@link ConfigurableEnvironment} may further customize
* property sources via the {@link #getPropertySources()} accessor, typically within
* an {@link org.springframework.context.ApplicationContextInitializer
* ApplicationContextInitializer}. For example:
* <pre>
* ConfigurableEnvironment env = new StandardEnvironment();
* env.getPropertySources().addLast(new PropertySourceX(...));
* </pre>
*
* @see MutablePropertySources
* @see PropertySourcesPropertyResolver
* @see org.springframework.context.ApplicationContextInitializer
*/
protected void customizePropertySources(MutablePropertySources propertySources) {
}
/**
* Return the set of reserved default profile names. This implementation returns
* {@value #RESERVED_DEFAULT_PROFILE_NAME}. Subclasses may override in order to
* customize the set of reserved names.
* @see #RESERVED_DEFAULT_PROFILE_NAME
* @see #doGetDefaultProfiles()
*/
protected Set<String> getReservedDefaultProfiles() {
return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
}
//---------------------------------------------------------------------

View File

@@ -49,7 +49,19 @@ public interface ConfigurableEnvironment extends Environment, ConfigurableProper
void setDefaultProfiles(String... profiles);
/**
* Return the {@link PropertySources} for this environment in mutable form
* Return the {@link PropertySources} for this {@code Environment} in mutable form,
* allowing for manipulation of the set of {@link PropertySource} objects that should
* be searched when resolving properties against this {@code Environment} object.
* The various {@link MutablePropertySources} methods such as
* {@link MutablePropertySources#addFirst addFirst},
* {@link MutablePropertySources#addFirst addLast},
* {@link MutablePropertySources#addFirst addBefore} and
* {@link MutablePropertySources#addFirst addAfter} allow for fine-grained control
* over property source ordering. This is useful, for example, in ensuring that
* certain user-defined property sources have search precedence over default property
* sources such as the set of system properties or the set of system environment
* variables.
* @see DefaultEnvironment#DefaultEnvironment()
*/
MutablePropertySources getPropertySources();

View File

@@ -83,17 +83,21 @@ public class DefaultEnvironment extends AbstractEnvironment {
/**
* Create a new {@code Environment} populated with property sources in the following order:
* Customize the set of property sources with those appropriate for any standard Java
* environment:
* <ul>
* <li>{@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME}
* <li>{@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}
* </ul>
* <p>Properties present in {@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME} will
* take precedence over those in {@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}.
* @see #getSystemProperties()
* @see #getSystemEnvironment()
*/
public DefaultEnvironment() {
getPropertySources().addFirst(new MapPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
getPropertySources().addFirst(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new MapPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}