标签:
1、顶层接口 PropertyResolver : 定义或者定义属性的方法
/* * Copyright 2002-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.core.env; /** * Interface for resolving properties against any underlying source. * * @author Chris Beams * @since 3.1 * @see Environment * @see PropertySourcesPropertyResolver */ public interface PropertyResolver { /** * Return whether the given property key is available for resolution, i.e., * the value for the given key is not {@code null}. */ boolean containsProperty(String key); /** * Return the property value associated with the given key, or {@code null} * if the key cannot be resolved. * @param key the property name to resolve * @see #getProperty(String, String) * @see #getProperty(String, Class) * @see #getRequiredProperty(String) */ String getProperty(String key); /** * Return the property value associated with the given key, or * {@code defaultValue} if the key cannot be resolved. * @param key the property name to resolve * @param defaultValue the default value to return if no value is found * @see #getRequiredProperty(String) * @see #getProperty(String, Class) */ String getProperty(String key, String defaultValue); /** * Return the property value associated with the given key, or {@code null} * if the key cannot be resolved. * @param key the property name to resolve * @param targetType the expected type of the property value * @see #getRequiredProperty(String, Class) */ <T> T getProperty(String key, Class<T> targetType); /** * Return the property value associated with the given key, or * {@code defaultValue} if the key cannot be resolved. * @param key the property name to resolve * @param targetType the expected type of the property value * @param defaultValue the default value to return if no value is found * @see #getRequiredProperty(String, Class) */ <T> T getProperty(String key, Class<T> targetType, T defaultValue); /** * Convert the property value associated with the given key to a {@code Class} * of type {@code T} or {@code null} if the key cannot be resolved. * @throws org.springframework.core.convert.ConversionException if class specified * by property value cannot be found or loaded or if targetType is not assignable * from class specified by property value * @see #getProperty(String, Class) */ <T> Class<T> getPropertyAsClass(String key, Class<T> targetType); /** * Return the property value associated with the given key (never {@code null}). * @throws IllegalStateException if the key cannot be resolved * @see #getRequiredProperty(String, Class) */ String getRequiredProperty(String key) throws IllegalStateException; /** * Return the property value associated with the given key, converted to the given * targetType (never {@code null}). * @throws IllegalStateException if the given key cannot be resolved */ <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException; /** * Resolve ${...} placeholders in the given text, replacing them with corresponding * property values as resolved by {@link #getProperty}. Unresolvable placeholders with * no default value are ignored and passed through unchanged. * @param text the String to resolve * @return the resolved String (never {@code null}) * @throws IllegalArgumentException if given text is {@code null} * @see #resolveRequiredPlaceholders * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String) */ String resolvePlaceholders(String text); /** * Resolve ${...} placeholders in the given text, replacing them with corresponding * property values as resolved by {@link #getProperty}. Unresolvable placeholders with * no default value will cause an IllegalArgumentException to be thrown. * @return the resolved String (never {@code null}) * @throws IllegalArgumentException if given text is {@code null} * or if any placeholders are unresolvable * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String, boolean) */ String resolveRequiredPlaceholders(String text) throws IllegalArgumentException; }
子接口:Environment 定义了获取环境的定义名称的一些方法
/* * Copyright 2002-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.core.env; /** * Interface representing the environment in which the current application is running. * Models two key aspects of the application environment: <em>profiles</em> and * <em>properties</em>. Methods related to property access are exposed via the * {@link PropertyResolver} superinterface. * * <p>A <em>profile</em> is a named, logical group of bean definitions to be registered * with the container only if the given profile is <em>active</em>. Beans may be assigned * to a profile whether defined in XML or via annotations; see the spring-beans 3.1 schema * or the {@link org.springframework.context.annotation.Profile @Profile} annotation for * syntax details. The role of the {@code Environment} object with relation to profiles is * in determining which profiles (if any) are currently {@linkplain #getActiveProfiles * active}, and which profiles (if any) should be {@linkplain #getDefaultProfiles active * by default}. * * <p><em>Properties</em> play an important role in almost all applications, and may * originate from a variety of sources: properties files, JVM system properties, system * environment variables, JNDI, servlet context parameters, ad-hoc Properties objects, * Maps, and so on. The role of the environment object with relation to properties is to * provide the user with a convenient service interface for configuring property sources * and resolving properties from them. * * <p>Beans managed within an {@code ApplicationContext} may register to be {@link * org.springframework.context.EnvironmentAware EnvironmentAware} or {@code @Inject} the * {@code Environment} in order to query profile state or resolve properties directly. * * <p>In most cases, however, application-level beans should not need to interact with the * {@code Environment} directly but instead may have to have {@code ${...}} property * values replaced by a property placeholder configurer such as * {@link org.springframework.context.support.PropertySourcesPlaceholderConfigurer * PropertySourcesPlaceholderConfigurer}, which itself is {@code EnvironmentAware} and * as of Spring 3.1 is registered by default when using * {@code <context:property-placeholder/>}. * * <p>Configuration of the environment object must be done through the * {@code ConfigurableEnvironment} interface, returned from all * {@code AbstractApplicationContext} subclass {@code getEnvironment()} methods. See * {@link ConfigurableEnvironment} Javadoc for usage examples demonstrating manipulation * of property sources prior to application context {@code refresh()}. * * @author Chris Beams * @since 3.1 * @see PropertyResolver * @see EnvironmentCapable * @see ConfigurableEnvironment * @see AbstractEnvironment * @see StandardEnvironment * @see org.springframework.context.EnvironmentAware * @see org.springframework.context.ConfigurableApplicationContext#getEnvironment * @see org.springframework.context.ConfigurableApplicationContext#setEnvironment * @see org.springframework.context.support.AbstractApplicationContext#createEnvironment */ public interface Environment extends PropertyResolver { /** * Return the set of profiles explicitly made active for this environment. Profiles * are used for creating logical groupings of bean definitions to be registered * conditionally, for example based on deployment environment. Profiles can be * activated by setting {@linkplain AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME * "spring.profiles.active"} as a system property or by calling * {@link ConfigurableEnvironment#setActiveProfiles(String...)}. * <p>If no profiles have explicitly been specified as active, then any {@linkplain * #getDefaultProfiles() default profiles} will automatically be activated. * @see #getDefaultProfiles * @see ConfigurableEnvironment#setActiveProfiles * @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME */ String[] getActiveProfiles(); /** * Return the set of profiles to be active by default when no active profiles have * been set explicitly. * @see #getActiveProfiles * @see ConfigurableEnvironment#setDefaultProfiles * @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME */ String[] getDefaultProfiles(); /** * Return whether one or more of the given profiles is active or, in the case of no * explicit active profiles, whether one or more of the given profiles is included in * the set of default profiles. If a profile begins with ‘!‘ the logic is inverted, * i.e. the method will return true if the given profile is <em>not</em> active. * For example, <pre class="code">env.acceptsProfiles("p1", "!p2")</pre> will * return {@code true} if profile ‘p1‘ is active or ‘p2‘ is not active. * @throws IllegalArgumentException if called with zero arguments * or if any profile is {@code null}, empty or whitespace-only * @see #getActiveProfiles * @see #getDefaultProfiles */ boolean acceptsProfiles(String... profiles); }
接着便是配置环境变量的接口 ConfigurableEnvironment :增加了一个ConfigurablePropertyResolver接口功能,可以ConfigurableConversionService getConversionService(),持有一个ConfigurableConversionService对象,可以在资源对象的类型转换时候调用,实现自己的逻辑
/* * Copyright 2002-2012 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.core.env; import java.util.Map; /** * Configuration interface to be implemented by most if not all {@link Environment} types. * Provides facilities for setting active and default profiles and manipulating underlying * property sources. Allows clients to set and validate required properties, customize the * conversion service and more through the {@link ConfigurablePropertyResolver} * superinterface. * * <h2>Manipulating property sources</h2> * <p>Property sources may be removed, reordered, or replaced; and additional * property sources may be added using the {@link MutablePropertySources} * instance returned from {@link #getPropertySources()}. The following examples * are against the {@link StandardEnvironment} implementation of * {@code ConfigurableEnvironment}, but are generally applicable to any implementation, * though particular default property sources may differ. * * <h4>Example: adding a new property source with highest search priority</h4> * <pre class="code"> * ConfigurableEnvironment environment = new StandardEnvironment(); * MutablePropertySources propertySources = environment.getPropertySources(); * Map<String, String> myMap = new HashMap<String, String>(); * myMap.put("xyz", "myValue"); * propertySources.addFirst(new MapPropertySource("MY_MAP", myMap)); * </pre> * * <h4>Example: removing the default system properties property source</h4> * <pre class="code"> * MutablePropertySources propertySources = environment.getPropertySources(); * propertySources.remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME) * </pre> * * <h4>Example: mocking the system environment for testing purposes</h4> * <pre class="code"> * MutablePropertySources propertySources = environment.getPropertySources(); * MockPropertySource mockEnvVars = new MockPropertySource().withProperty("xyz", "myValue"); * propertySources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, mockEnvVars); * </pre> * * When an {@link Environment} is being used by an {@code ApplicationContext}, it is * important that any such {@code PropertySource} manipulations be performed * <em>before</em> the context‘s {@link * org.springframework.context.support.AbstractApplicationContext#refresh() refresh()} * method is called. This ensures that all property sources are available during the * container bootstrap process, including use by {@linkplain * org.springframework.context.support.PropertySourcesPlaceholderConfigurer property * placeholder configurers}. * * * @author Chris Beams * @since 3.1 * @see StandardEnvironment * @see org.springframework.context.ConfigurableApplicationContext#getEnvironment */ public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver { /** * Specify the set of profiles active for this {@code Environment}. Profiles are * evaluated during container bootstrap to determine whether bean definitions * should be registered with the container. * <p>Any existing active profiles will be replaced with the given arguments; call * with zero arguments to clear the current set of active profiles. Use * {@link #addActiveProfile} to add a profile while preserving the existing set. * @see #addActiveProfile * @see #setDefaultProfiles * @see org.springframework.context.annotation.Profile * @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME * @throws IllegalArgumentException if any profile is null, empty or whitespace-only */ void setActiveProfiles(String... profiles); /** * Add a profile to the current set of active profiles. * @see #setActiveProfiles * @throws IllegalArgumentException if the profile is null, empty or whitespace-only */ void addActiveProfile(String profile); /** * Specify the set of profiles to be made active by default if no other profiles * are explicitly made active through {@link #setActiveProfiles}. * @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME * @throws IllegalArgumentException if any profile is null, empty or whitespace-only */ void setDefaultProfiles(String... profiles); /** * 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 AbstractEnvironment#customizePropertySources */ MutablePropertySources getPropertySources(); /** * Return the value of {@link System#getenv()} if allowed by the current * {@link SecurityManager}, otherwise return a map implementation that will attempt * to access individual keys using calls to {@link System#getenv(String)}. * <p>Note that most {@link Environment} implementations will include this system * environment map as a default {@link PropertySource} to be searched. Therefore, it * is recommended that this method not be used directly unless bypassing other * property sources is expressly intended. * <p>Calls to {@link Map#get(Object)} on the Map returned will never throw * {@link IllegalAccessException}; in cases where the SecurityManager forbids access * to a property, {@code null} will be returned and an INFO-level log message will be * issued noting the exception. */ Map<String, Object> getSystemEnvironment(); /** * Return the value of {@link System#getProperties()} if allowed by the current * {@link SecurityManager}, otherwise return a map implementation that will attempt * to access individual keys using calls to {@link System#getProperty(String)}. * <p>Note that most {@code Environment} implementations will include this system * properties map as a default {@link PropertySource} to be searched. Therefore, it is * recommended that this method not be used directly unless bypassing other property * sources is expressly intended. * <p>Calls to {@link Map#get(Object)} on the Map returned will never throw * {@link IllegalAccessException}; in cases where the SecurityManager forbids access * to a property, {@code null} will be returned and an INFO-level log message will be * issued noting the exception. */ Map<String, Object> getSystemProperties(); /** * Append the given parent environment‘s active profiles, default profiles and * property sources to this (child) environment‘s respective collections of each. * <p>For any identically-named {@code PropertySource} instance existing in both * parent and child, the child instance is to be preserved and the parent instance * discarded. This has the effect of allowing overriding of property sources by the * child as well as avoiding redundant searches through common property source types, * e.g. system environment and system properties. * <p>Active and default profile names are also filtered for duplicates, to avoid * confusion and redundant storage. * <p>The parent environment remains unmodified in any case. Note that any changes to * the parent environment occurring after the call to {@code merge} will not be * reflected in the child. Therefore, care should be taken to configure parent * property sources and profile information prior to calling {@code merge}. * @param parent the environment to merge with * @since 3.1.2 * @see org.springframework.context.support.AbstractApplicationContext#setParent */ void merge(ConfigurableEnvironment parent); }
其中ConfigurablePropertyResolver:这个对象是操作converting property values from one type to another
/* * Copyright 2002-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.core.env; import org.springframework.core.convert.support.ConfigurableConversionService; /** * Configuration interface to be implemented by most if not all {@link PropertyResolver * PropertyResolver} types. Provides facilities for accessing and customizing the * {@link org.springframework.core.convert.ConversionService ConversionService} used when * converting property values from one type to another. * * @author Chris Beams * @since 3.1 */ public interface ConfigurablePropertyResolver extends PropertyResolver { /** * @return the {@link ConfigurableConversionService} used when performing type * conversions on properties. * <p>The configurable nature of the returned conversion service allows for * the convenient addition and removal of individual {@code Converter} instances: * <pre class="code"> * ConfigurableConversionService cs = env.getConversionService(); * cs.addConverter(new FooConverter()); * </pre> * @see PropertyResolver#getProperty(String, Class) * @see org.springframework.core.convert.converter.ConverterRegistry#addConverter */ ConfigurableConversionService getConversionService(); /** * Set the {@link ConfigurableConversionService} to be used when performing type * conversions on properties. * <p><strong>Note:</strong> as an alternative to fully replacing the {@code * ConversionService}, consider adding or removing individual {@code Converter} * instances by drilling into {@link #getConversionService()} and calling methods * such as {@code #addConverter}. * @see PropertyResolver#getProperty(String, Class) * @see #getConversionService() * @see org.springframework.core.convert.converter.ConverterRegistry#addConverter */ void setConversionService(ConfigurableConversionService conversionService); /** * Set the prefix that placeholders replaced by this resolver must begin with. */ void setPlaceholderPrefix(String placeholderPrefix); /** * Set the suffix that placeholders replaced by this resolver must end with. */ void setPlaceholderSuffix(String placeholderSuffix); /** * Specify the separating character between the placeholders replaced by this * resolver and their associated default value, or {@code null} if no such * special character should be processed as a value separator. */ void setValueSeparator(String valueSeparator); /** * Set whether to throw an exception when encountering an unresolvable placeholder * nested within the value of a given property. A {@code false} value indicates strict * resolution, i.e. that an exception will be thrown. A {@code true} value indicates * that unresolvable nested placeholders should be passed through in their unresolved * ${...} form. * <p>Implementations of {@link #getProperty(String)} and its variants must inspect * the value set here to determine correct behavior when property values contain * unresolvable placeholders. * @since 3.2 */ void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders); /** * Specify which properties must be present, to be verified by * {@link #validateRequiredProperties()}. */ void setRequiredProperties(String... requiredProperties); /** * Validate that each of the properties specified by * {@link #setRequiredProperties} is present and resolves to a * non-{@code null} value. * @throws MissingRequiredPropertiesException if any of the required * properties are not resolvable. */ void validateRequiredProperties() throws MissingRequiredPropertiesException; }
第四层为AbstractEnvironment 可以接收自定义的profile,设置默认的profile,有个customizePropertySources(MutablePropertySources)方法需要子类实现的,设置数据源
/* * Copyright 2002-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.core.env; import java.security.AccessControlException; import java.util.Collections; import java.util.LinkedHashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.core.SpringProperties; import org.springframework.core.convert.support.ConfigurableConversionService; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import static java.lang.String.*; import static org.springframework.util.StringUtils.*; /** * Abstract base class for {@link Environment} implementations. Supports the notion of * reserved default profile names and enables specifying active and default profiles * through the {@link #ACTIVE_PROFILES_PROPERTY_NAME} and * {@link #DEFAULT_PROFILES_PROPERTY_NAME} properties. * * <p>Concrete subclasses differ primarily on which {@link PropertySource} objects they * add by default. {@code AbstractEnvironment} adds none. Subclasses should contribute * property sources through the protected {@link #customizePropertySources(MutablePropertySources)} * hook, while clients should customize using {@link ConfigurableEnvironment#getPropertySources()} * and working against the {@link MutablePropertySources} API. * See {@link ConfigurableEnvironment} javadoc for usage examples. * * @author Chris Beams * @author Juergen Hoeller * @since 3.1 * @see ConfigurableEnvironment * @see StandardEnvironment */ public abstract class AbstractEnvironment implements ConfigurableEnvironment { /** * System property that instructs Spring to ignore system environment variables, * i.e. to never attempt to retrieve such a variable via {@link System#getenv()}. * <p>The default is "false", falling back to system environment variable checks if a * Spring environment property (e.g. a placeholder in a configuration String) isn‘t * resolvable otherwise. Consider switching this flag to "true" if you experience * log warnings from {@code getenv} calls coming from Spring, e.g. on WebSphere * with strict SecurityManager settings and AccessControlExceptions warnings. * @see #suppressGetenvAccess() */ public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore"; /** * Name of property to set to specify active profiles: {@value}. Value may be comma * delimited. * <p>Note that certain shell environments such as Bash disallow the use of the period * character in variable names. Assuming that Spring‘s {@link SystemEnvironmentPropertySource} * is in use, this property may be specified as an environment variable as * {@code SPRING_PROFILES_ACTIVE}. * @see ConfigurableEnvironment#setActiveProfiles */ public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active"; /** * Name of property to set to specify profiles active by default: {@value}. Value may * be comma delimited. * <p>Note that certain shell environments such as Bash disallow the use of the period * character in variable names. Assuming that Spring‘s {@link SystemEnvironmentPropertySource} * is in use, this property may be specified as an environment variable as * {@code SPRING_PROFILES_DEFAULT}. * @see ConfigurableEnvironment#setDefaultProfiles */ public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default"; /** * Name of reserved default profile name: {@value}. If no default profile names are * explicitly and no active profile names are explicitly set, this profile will * automatically be activated by default. * @see #getReservedDefaultProfiles * @see ConfigurableEnvironment#setDefaultProfiles * @see ConfigurableEnvironment#setActiveProfiles * @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME * @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME */ protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default"; protected final Log logger = LogFactory.getLog(getClass()); private Set<String> activeProfiles = new LinkedHashSet<String>(); private Set<String> defaultProfiles = new LinkedHashSet<String>(getReservedDefaultProfiles()); private final MutablePropertySources propertySources = new MutablePropertySources(this.logger); private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources); /** * Create a new {@code Environment} instance, calling back to * {@link #customizePropertySources(MutablePropertySources)} during construction to * allow subclasses to contribute or manipulate {@link PropertySource} instances as * appropriate. * @see #customizePropertySources(MutablePropertySources) */ public AbstractEnvironment() { customizePropertySources(this.propertySources); if (this.logger.isDebugEnabled()) { this.logger.debug(format( "Initialized %s with PropertySources %s", getClass().getSimpleName(), this.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 { * @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 { * @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 class="code"> * public class Level2Environment extends Level1Environment { * @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*}, * {@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 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 class="code"> * ConfigurableEnvironment env = new StandardEnvironment(); * env.getPropertySources().addLast(new PropertySourceX(...)); * </pre> * * <h2>A warning about instance variable access</h2> * Instance variables declared in subclasses and having default initial values should * <em>not</em> be accessed from within this method. Due to Java object creation * lifecycle constraints, any initial value will not yet be assigned when this * callback is invoked by the {@link #AbstractEnvironment()} constructor, which may * lead to a {@code NullPointerException} or other problems. If you need to access * default values of instance variables, leave this method as a no-op and perform * property source manipulation and instance variable access directly within the * subclass constructor. Note that <em>assigning</em> values to instance variables is * not problematic; it is only attempting to read default values that must be avoided. * * @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); } //--------------------------------------------------------------------- // Implementation of ConfigurableEnvironment interface //--------------------------------------------------------------------- @Override public String[] getActiveProfiles() { return StringUtils.toStringArray(doGetActiveProfiles()); } /** * Return the set of active profiles as explicitly set through * {@link #setActiveProfiles} or if the current set of active profiles * is empty, check for the presence of the {@value #ACTIVE_PROFILES_PROPERTY_NAME} * property and assign its value to the set of active profiles. * @see #getActiveProfiles() * @see #ACTIVE_PROFILES_PROPERTY_NAME */ protected Set<String> doGetActiveProfiles() { if (this.activeProfiles.isEmpty()) { String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME); if (StringUtils.hasText(profiles)) { setActiveProfiles(commaDelimitedListToStringArray(trimAllWhitespace(profiles))); } } return this.activeProfiles; } @Override public void setActiveProfiles(String... profiles) { Assert.notNull(profiles, "Profile array must not be null"); this.activeProfiles.clear(); for (String profile : profiles) { validateProfile(profile); this.activeProfiles.add(profile); } } @Override public void addActiveProfile(String profile) { if (this.logger.isDebugEnabled()) { this.logger.debug(format("Activating profile ‘%s‘", profile)); } validateProfile(profile); doGetActiveProfiles(); this.activeProfiles.add(profile); } @Override public String[] getDefaultProfiles() { return StringUtils.toStringArray(doGetDefaultProfiles()); } /** * Return the set of default profiles explicitly set via * {@link #setDefaultProfiles(String...)} or if the current set of default profiles * consists only of {@linkplain #getReservedDefaultProfiles() reserved default * profiles}, then check for the presence of the * {@value #DEFAULT_PROFILES_PROPERTY_NAME} property and assign its value (if any) * to the set of default profiles. * @see #AbstractEnvironment() * @see #getDefaultProfiles() * @see #DEFAULT_PROFILES_PROPERTY_NAME * @see #getReservedDefaultProfiles() */ protected Set<String> doGetDefaultProfiles() { if (this.defaultProfiles.equals(getReservedDefaultProfiles())) { String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME); if (StringUtils.hasText(profiles)) { setDefaultProfiles(commaDelimitedListToStringArray(trimAllWhitespace(profiles))); } } return this.defaultProfiles; } /** * Specify the set of profiles to be made active by default if no other profiles * are explicitly made active through {@link #setActiveProfiles}. * <p>Calling this method removes overrides any reserved default profiles * that may have been added during construction of the environment. * @see #AbstractEnvironment() * @see #getReservedDefaultProfiles() */ @Override public void setDefaultProfiles(String... profiles) { Assert.notNull(profiles, "Profile array must not be null"); this.defaultProfiles.clear(); for (String profile : profiles) { validateProfile(profile); this.defaultProfiles.add(profile); } } @Override public boolean acceptsProfiles(String... profiles) { Assert.notEmpty(profiles, "Must specify at least one profile"); for (String profile : profiles) { if (profile != null && profile.length() > 0 && profile.charAt(0) == ‘!‘) { if (!isProfileActive(profile.substring(1))) { return true; } } else if (isProfileActive(profile)) { return true; } } return false; } /** * Return whether the given profile is active, or if active profiles are empty * whether the profile should be active by default. * @throws IllegalArgumentException per {@link #validateProfile(String)} */ protected boolean isProfileActive(String profile) { validateProfile(profile); return doGetActiveProfiles().contains(profile) || (doGetActiveProfiles().isEmpty() && doGetDefaultProfiles().contains(profile)); } /** * Validate the given profile, called internally prior to adding to the set of * active or default profiles. * <p>Subclasses may override to impose further restrictions on profile syntax. * @throws IllegalArgumentException if the profile is null, empty, whitespace-only or * begins with the profile NOT operator (!). * @see #acceptsProfiles * @see #addActiveProfile * @see #setDefaultProfiles */ protected void validateProfile(String profile) { if (!StringUtils.hasText(profile)) { throw new IllegalArgumentException("Invalid profile [" + profile + "]: must contain text"); } if (profile.charAt(0) == ‘!‘) { throw new IllegalArgumentException("Invalid profile [" + profile + "]: must not begin with ! operator"); } } @Override public MutablePropertySources getPropertySources() { return this.propertySources; } @Override @SuppressWarnings("unchecked") public Map<String, Object> getSystemEnvironment() { if (suppressGetenvAccess()) { return Collections.emptyMap(); } try { return (Map) System.getenv(); } catch (AccessControlException ex) { return (Map) new ReadOnlySystemAttributesMap() { @Override protected String getSystemAttribute(String attributeName) { try { return System.getenv(attributeName); } catch (AccessControlException ex) { if (logger.isInfoEnabled()) { logger.info(format("Caught AccessControlException when accessing system " + "environment variable [%s]; its value will be returned [null]. Reason: %s", attributeName, ex.getMessage())); } return null; } } }; } } /** * Determine whether to suppress {@link System#getenv()}/{@link System#getenv(String)} * access for the purposes of {@link #getSystemEnvironment()}. * <p>If this method returns {@code true}, an empty dummy Map will be used instead * of the regular system environment Map, never even trying to call {@code getenv} * and therefore avoiding security manager warnings (if any). * <p>The default implementation checks for the "spring.getenv.ignore" system property, * returning {@code true} if its value equals "true" in any case. * @see #IGNORE_GETENV_PROPERTY_NAME * @see SpringProperties#getFlag */ protected boolean suppressGetenvAccess() { return SpringProperties.getFlag(IGNORE_GETENV_PROPERTY_NAME); } @Override @SuppressWarnings("unchecked") public Map<String, Object> getSystemProperties() { try { return (Map) System.getProperties(); } catch (AccessControlException ex) { return (Map) new ReadOnlySystemAttributesMap() { @Override protected String getSystemAttribute(String attributeName) { try { return System.getProperty(attributeName); } catch (AccessControlException ex) { if (logger.isInfoEnabled()) { logger.info(format("Caught AccessControlException when accessing system " + "property [%s]; its value will be returned [null]. Reason: %s", attributeName, ex.getMessage())); } return null; } } }; } } @Override public void merge(ConfigurableEnvironment parent) { for (PropertySource<?> ps : parent.getPropertySources()) { if (!this.propertySources.contains(ps.getName())) { this.propertySources.addLast(ps); } } for (String profile : parent.getActiveProfiles()) { this.activeProfiles.add(profile); } if (parent.getDefaultProfiles().length > 0) { this.defaultProfiles.remove(RESERVED_DEFAULT_PROFILE_NAME); for (String profile : parent.getDefaultProfiles()) { this.defaultProfiles.add(profile); } } } //--------------------------------------------------------------------- // Implementation of ConfigurablePropertyResolver interface //--------------------------------------------------------------------- @Override public ConfigurableConversionService getConversionService() { return this.propertyResolver.getConversionService(); } @Override public void setConversionService(ConfigurableConversionService conversionService) { this.propertyResolver.setConversionService(conversionService); } @Override public void setPlaceholderPrefix(String placeholderPrefix) { this.propertyResolver.setPlaceholderPrefix(placeholderPrefix); } @Override public void setPlaceholderSuffix(String placeholderSuffix) { this.propertyResolver.setPlaceholderSuffix(placeholderSuffix); } @Override public void setValueSeparator(String valueSeparator) { this.propertyResolver.setValueSeparator(valueSeparator); } @Override public void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders) { this.propertyResolver.setIgnoreUnresolvableNestedPlaceholders(ignoreUnresolvableNestedPlaceholders); } @Override public void setRequiredProperties(String... requiredProperties) { this.propertyResolver.setRequiredProperties(requiredProperties); } @Override public void validateRequiredProperties() throws MissingRequiredPropertiesException { this.propertyResolver.validateRequiredProperties(); } //--------------------------------------------------------------------- // Implementation of PropertyResolver interface //--------------------------------------------------------------------- @Override public boolean containsProperty(String key) { return this.propertyResolver.containsProperty(key); } @Override public String getProperty(String key) { return this.propertyResolver.getProperty(key); } @Override public String getProperty(String key, String defaultValue) { return this.propertyResolver.getProperty(key, defaultValue); } @Override public <T> T getProperty(String key, Class<T> targetType) { return this.propertyResolver.getProperty(key, targetType); } @Override public <T> T getProperty(String key, Class<T> targetType, T defaultValue) { return this.propertyResolver.getProperty(key, targetType, defaultValue); } @Override public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) { return this.propertyResolver.getPropertyAsClass(key, targetType); } @Override public String getRequiredProperty(String key) throws IllegalStateException { return this.propertyResolver.getRequiredProperty(key); } @Override public <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException { return this.propertyResolver.getRequiredProperty(key, targetType); } @Override public String resolvePlaceholders(String text) { return this.propertyResolver.resolvePlaceholders(text); } @Override public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException { return this.propertyResolver.resolveRequiredPlaceholders(text); } @Override public String toString() { return format("%s {activeProfiles=%s, defaultProfiles=%s, propertySources=%s}", getClass().getSimpleName(), this.activeProfiles, this.defaultProfiles, this.propertySources); } }
底层子类StandardEnvironment
/* * Copyright 2002-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.core.env; /** * {@link Environment} implementation suitable for use in ‘standard‘ (i.e. non-web) * applications. * * <p>In addition to the usual functions of a {@link ConfigurableEnvironment} such as * property resolution and profile-related operations, this implementation configures two * default property sources, to be searched in the following order: * <ul> * <li>{@linkplain AbstractEnvironment#getSystemProperties() system properties} * <li>{@linkplain AbstractEnvironment#getSystemEnvironment() system environment variables} * </ul> * * That is, if the key "xyz" is present both in the JVM system properties as well as in * the set of environment variables for the current process, the value of key "xyz" from * system properties will return from a call to {@code environment.getProperty("xyz")}. * This ordering is chosen by default because system properties are per-JVM, while * environment variables may be the same across many JVMs on a given system. Giving * system properties precedence allows for overriding of environment variables on a * per-JVM basis. * * <p>These default property sources may be removed, reordered, or replaced; and * additional property sources may be added using the {@link MutablePropertySources} * instance available from {@link #getPropertySources()}. See * {@link ConfigurableEnvironment} Javadoc for usage examples. * * <p>See {@link SystemEnvironmentPropertySource} javadoc for details on special handling * of property names in shell environments (e.g. Bash) that disallow period characters in * variable names. * * @author Chris Beams * @since 3.1 * @see ConfigurableEnvironment * @see SystemEnvironmentPropertySource * @see org.springframework.web.context.support.StandardServletEnvironment */ public class StandardEnvironment extends AbstractEnvironment { /** System environment property source name: {@value} */ public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment"; /** JVM system properties property source name: {@value} */ public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties"; /** * 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 AbstractEnvironment#customizePropertySources(MutablePropertySources) * @see #getSystemProperties() * @see #getSystemEnvironment() */ @Override protected void customizePropertySources(MutablePropertySources propertySources) { propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties())); propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment())); } }
标签:
原文地址:http://my.oschina.net/u/867830/blog/407191