Spring源码解读:Envrionment接口

来源:互联网 发布:mac物理地址不匹配 编辑:程序博客网 时间:2024/06/09 15:36

spring提供了普通结构通用的环境机制,可以使用默认或者自定义的环境去配置一些变量或者设置,便于正式运行的环境跟开发,测试的环境分开。

PropertyResolver接口中的方法及定义

/** * 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 T 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 T 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 string, 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 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, converted to the given * targetType (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} * @throws IllegalArgumentException if any placeholders are unresolvable * @see org.springframework.util.SystemPropertyUtils#resolvePlaceholders(String, boolean) */String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;}

子接口Environment 定义了获取环境的定义名称的一些方法

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>${...}</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 * @throws IllegalArgumentException if called with zero arguments * @throws IllegalArgumentException if any profile is null, empty or whitespace-only * @see #getActiveProfiles * @see #getDefaultProfiles */boolean acceptsProfiles(String... profiles);}

接着便是配置环境变量的接口 ConfigurableEnvironment :增加了一个ConfigurablePropertyResolver接口功能,可以ConfigurableConversionService getConversionService(),持有一个ConfigurableConversionService对象,可以在资源对象的类型转换时候调用,实现自己的逻辑

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

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);/** * 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)方法需要子类实现的,设置数据源

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.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 * @since 3.1 * @see ConfigurableEnvironment * @see StandardEnvironment */public abstract class AbstractEnvironment implements ConfigurableEnvironment {/** * 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() {String name = getClass().getSimpleName();if (this.logger.isDebugEnabled()) {this.logger.debug(format("Initializing new %s", name));}customizePropertySources(this.propertySources);if (this.logger.isDebugEnabled()) {this.logger.debug(format("Initialized %s with PropertySources %s", name, 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>, * {@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 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//---------------------------------------------------------------------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 = this.getProperty(ACTIVE_PROFILES_PROPERTY_NAME);if (StringUtils.hasText(profiles)) {setActiveProfiles(commaDelimitedListToStringArray(trimAllWhitespace(profiles)));}}return this.activeProfiles;}public void setActiveProfiles(String... profiles) {Assert.notNull(profiles, "Profile array must not be null");this.activeProfiles.clear();for (String profile : profiles) {addActiveProfile(profile);}}public void addActiveProfile(String profile) {if (this.logger.isDebugEnabled()) {this.logger.debug(format("Activating profile '%s'", profile));}validateProfile(profile);this.activeProfiles.add(profile);}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 = this.getProperty(DEFAULT_PROFILES_PROPERTY_NAME);if (StringUtils.hasText(profiles)) {setDefaultProfiles(commaDelimitedListToStringArray(trimAllWhitespace(profiles)));}}return this.defaultProfiles;}/** * {@inheritDoc} * <p>Calling this method removes overrides any reserved default profiles * that may have been added during construction of the environment. * @see #AbstractEnvironment() * @see #getReservedDefaultProfiles() */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);}}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) == '!') {return !isProfileActive(profile.substring(1));}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) {Assert.hasText(profile, "Invalid profile [" + profile + "]: must contain text");Assert.isTrue(profile.charAt(0) != '!',"Invalid profile [" + profile + "]: must not begin with the ! operator");}public MutablePropertySources getPropertySources() {return this.propertySources;}@SuppressWarnings("unchecked")public Map<String, Object> getSystemEnvironment() {Map<String, ?> systemEnvironment;try {systemEnvironment = System.getenv();}catch (AccessControlException ex) {systemEnvironment = new ReadOnlySystemAttributesMap() {@Overrideprotected String getSystemAttribute(String variableName) {try {return System.getenv(variableName);}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",variableName, ex.getMessage()));}return null;}}};}return (Map<String, Object>) systemEnvironment;}@SuppressWarnings({"unchecked", "rawtypes"})public Map<String, Object> getSystemProperties() {Map systemProperties;try {systemProperties = System.getProperties();}catch (AccessControlException ex) {systemProperties = new ReadOnlySystemAttributesMap() {@Overrideprotected String getSystemAttribute(String propertyName) {try {return System.getProperty(propertyName);}catch (AccessControlException ex) {if (logger.isInfoEnabled()) {logger.info(format("Caught AccessControlException when " +"accessing system property [%s]; its value will be " +"returned [null]. Reason: %s",propertyName, ex.getMessage()));}return null;}}};}return systemProperties;}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//---------------------------------------------------------------------public boolean containsProperty(String key) {return this.propertyResolver.containsProperty(key);}public String getProperty(String key) {return this.propertyResolver.getProperty(key);}public String getProperty(String key, String defaultValue) {return this.propertyResolver.getProperty(key, defaultValue);}public <T> T getProperty(String key, Class<T> targetType) {return this.propertyResolver.getProperty(key, targetType);}public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {return this.propertyResolver.getProperty(key, targetType, defaultValue);};public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) {return this.propertyResolver.getPropertyAsClass(key, targetType);}public String getRequiredProperty(String key) throws IllegalStateException {return this.propertyResolver.getRequiredProperty(key);}public <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException {return this.propertyResolver.getRequiredProperty(key, targetType);}public void setRequiredProperties(String... requiredProperties) {this.propertyResolver.setRequiredProperties(requiredProperties);}public void validateRequiredProperties() throws MissingRequiredPropertiesException {this.propertyResolver.validateRequiredProperties();}public String resolvePlaceholders(String text) {return this.propertyResolver.resolvePlaceholders(text);}public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {return this.propertyResolver.resolveRequiredPlaceholders(text);}public void setConversionService(ConfigurableConversionService conversionService) {this.propertyResolver.setConversionService(conversionService);}public ConfigurableConversionService getConversionService() {return this.propertyResolver.getConversionService();}public void setPlaceholderPrefix(String placeholderPrefix) {this.propertyResolver.setPlaceholderPrefix(placeholderPrefix);}public void setPlaceholderSuffix(String placeholderSuffix) {this.propertyResolver.setPlaceholderSuffix(placeholderSuffix);}public void setValueSeparator(String valueSeparator) {this.propertyResolver.setValueSeparator(valueSeparator);}@Overridepublic String toString() {return format("%s {activeProfiles=%s, defaultProfiles=%s, propertySources=%s}",getClass().getSimpleName(), this.activeProfiles, this.defaultProfiles,this.propertySources);}}
底层子类StandardEnvironment

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() */@Overrideprotected void customizePropertySources(MutablePropertySources propertySources) {propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));}}

StandardServletEnvironment子类

package org.springframework.web.context.support;import javax.servlet.ServletConfig;import javax.servlet.ServletContext;import org.springframework.core.env.Environment;import org.springframework.core.env.MutablePropertySources;import org.springframework.core.env.PropertySource;import org.springframework.core.env.PropertySource.StubPropertySource;import org.springframework.core.env.StandardEnvironment;import org.springframework.jndi.JndiLocatorDelegate;import org.springframework.jndi.JndiPropertySource;import org.springframework.web.context.ConfigurableWebEnvironment;/** * {@link Environment} implementation to be used by {@code Servlet}-based web * applications. All web-related (servlet-based) {@code ApplicationContext} classes * initialize an instance by default. * * <p>Contributes {@code ServletConfig}, {@code ServletContext}, and JNDI-based * {@link PropertySource} instances. See {@link #customizePropertySources} method * documentation for details. * * @author Chris Beams * @since 3.1 * @see StandardEnvironment */public class StandardServletEnvironment extends StandardEnvironmentimplements ConfigurableWebEnvironment {/** Servlet context init parameters property source name: {@value} */public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";/** Servlet config init parameters property source name: {@value} */public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";/** JNDI property source name: {@value} */public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";/** * Customize the set of property sources with those contributed by superclasses as * well as those appropriate for standard servlet-based environments: * <ul> * <li>{@value #SERVLET_CONFIG_PROPERTY_SOURCE_NAME} * <li>{@value #SERVLET_CONTEXT_PROPERTY_SOURCE_NAME} * <li>{@value #JNDI_PROPERTY_SOURCE_NAME} * </ul> * <p>Properties present in {@value #SERVLET_CONFIG_PROPERTY_SOURCE_NAME} will * take precedence over those in {@value #SERVLET_CONTEXT_PROPERTY_SOURCE_NAME}, and * properties found in either of the above take precedence over those found in * {@value #JNDI_PROPERTY_SOURCE_NAME}. * <p>Properties in any of the above will take precedence over system properties and * environment variables contributed by the {@link StandardEnvironment} superclass. * <p>The {@code Servlet}-related property sources are added as {@link * StubPropertySource stubs} at this stage, and will be {@linkplain * #initPropertySources(ServletContext) fully initialized} once the actual * {@link ServletContext} object becomes available. * @see StandardEnvironment#customizePropertySources * @see org.springframework.core.env.AbstractEnvironment#customizePropertySources * @see ServletConfigPropertySource * @see ServletContextPropertySource * @see org.springframework.jndi.JndiPropertySource * @see org.springframework.context.support.AbstractApplicationContext#initPropertySources * @see #initPropertySources(ServletContext) */@Overrideprotected void customizePropertySources(MutablePropertySources propertySources) {propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));}super.customizePropertySources(propertySources);}public void initPropertySources(ServletContext servletContext, ServletConfig servletConfig) {WebApplicationContextUtils.initServletPropertySources(this.getPropertySources(), servletContext, servletConfig);}}

上面的大概简述了下spring的环境机制,

这个是我个人的思路,首先这个顶层的接口是个 PropertyResolver,即是对Property进行相关操作的的类,根据程序=数据算法+数据的原理,这个算法是PropertyResolver,这个数据是Property。

那么Property的设计结构是啥哪,他是这个玩意

看源码就是一个String的name一个Object的value,是个键值对儿!

PropertySource源码

package org.springframework.core.env;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.springframework.util.Assert;/** * Abstract base class representing a source of name/value property pairs. The underlying * {@linkplain #getSource() source object} may be of any type {@code T} that encapsulates * properties. Examples include {@link java.util.Properties} objects, {@link java.util.Map} * objects, {@code ServletContext} and {@code ServletConfig} objects (for access to init * parameters). Explore the {@code PropertySource} type hierarchy to see provided * implementations. * * <p>{@code PropertySource} objects are not typically used in isolation, but rather * through a {@link PropertySources} object, which aggregates property sources and in * conjunction with a {@link PropertyResolver} implementation that can perform * precedence-based searches across the set of {@code PropertySources}. * * <p>{@code PropertySource} identity is determined not based on the content of * encapsulated properties, but rather based on the {@link #getName() name} of the * {@code PropertySource} alone. This is useful for manipulating {@code PropertySource} * objects when in collection contexts. See operations in {@link MutablePropertySources} * as well as the {@link #named(String)} and {@link #toString()} methods for details. * * <p>Note that when working with @{@link * org.springframework.context.annotation.Configuration Configuration} classes that * the @{@link org.springframework.context.annotation.PropertySource PropertySource} * annotation provides a convenient and declarative way of adding property sources to the * enclosing {@code Environment}. * * @author Chris Beams * @since 3.1 * @see PropertySources * @see PropertyResolver * @see PropertySourcesPropertyResolver * @see MutablePropertySources * @see org.springframework.context.annotation.PropertySource */public abstract class PropertySource<T> {protected final Log logger = LogFactory.getLog(this.getClass());protected final String name;protected final T source;/** * Create a new {@code PropertySource} with the given name and source object. */public PropertySource(String name, T source) {Assert.hasText(name, "Property source name must contain at least one character");Assert.notNull(source, "Property source must not be null");this.name = name;this.source = source;}/** * Create a new {@code PropertySource} with the given name and with a new {@code Object} * instance as the underlying source. * <p>Often useful in testing scenarios when creating * anonymous implementations that never query an actual source, but rather return * hard-coded values. */@SuppressWarnings("unchecked")public PropertySource(String name) {this(name, (T) new Object());}/** * Return the name of this {@code PropertySource} */public String getName() {return this.name;}/** * Return the underlying source object for this {@code PropertySource}. */public T getSource() {return source;}/** * Return whether this {@code PropertySource} contains the given name. * <p>This implementation simply checks for a null return value * from {@link #getProperty(String)}. Subclasses may wish to * implement a more efficient algorithm if possible. * @param name the property name to find */public boolean containsProperty(String name) {return this.getProperty(name) != null;}/** * Return the value associated with the given name, {@code null} if not found. * @param name the property to find * @see PropertyResolver#getRequiredProperty(String) */public abstract Object getProperty(String name);/** * Return a hashcode derived from the {@code name} property of this {@code PropertySource} * object. */@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((this.name == null) ? 0 : this.name.hashCode());return result;}/** * This {@code PropertySource} object is equal to the given object if: * <ul> *   <li>they are the same instance *   <li>the {@code name} properties for both objects are equal * </ul> * * <P>No properties other than {@code name} are evaluated. */@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (!(obj instanceof PropertySource))return false;PropertySource<?> other = (PropertySource<?>) obj;if (this.name == null) {if (other.name != null)return false;} else if (!this.name.equals(other.name))return false;return true;}/** * Produce concise output (type and name) if the current log level does not include * debug. If debug is enabled, produce verbose output including hashcode of the * PropertySource instance and every name/value property pair. * * This variable verbosity is useful as a property source such as system properties * or environment variables may contain an arbitrary number of property pairs, * potentially leading to difficult to read exception and log messages. * * @see Log#isDebugEnabled() */@Overridepublic String toString() {if (logger.isDebugEnabled()) {return String.format("%s@%s [name='%s', properties=%s]",this.getClass().getSimpleName(), System.identityHashCode(this), this.name, this.source);}return String.format("%s [name='%s']",this.getClass().getSimpleName(), this.name);}/** * Return a {@code PropertySource} implementation intended for collection comparison purposes only. * * <p>Primarily for internal use, but given a collection of {@code PropertySource} objects, may be * used as follows: * <pre class="code"> * {@code List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>(); * sources.add(new MapPropertySource("sourceA", mapA)); * sources.add(new MapPropertySource("sourceB", mapB)); * assert sources.contains(PropertySource.named("sourceA")); * assert sources.contains(PropertySource.named("sourceB")); * assert !sources.contains(PropertySource.named("sourceC")); * }</pre> * * The returned {@code PropertySource} will throw {@code UnsupportedOperationException} * if any methods other than {@code equals(Object)}, {@code hashCode()}, and {@code toString()} * are called. * * @param name the name of the comparison {@code PropertySource} to be created and returned. */public static PropertySource<?> named(String name) {return new ComparisonPropertySource(name);}/** * {@code PropertySource} to be used as a placeholder in cases where an actual * property source cannot be eagerly initialized at application context * creation time.  For example, a {@code ServletContext}-based property source * must wait until the {@code ServletContext} object is available to its enclosing * {@code ApplicationContext}.  In such cases, a stub should be used to hold the * intended default position/order of the property source, then be replaced * during context refresh. * * @see org.springframework.context.support.AbstractApplicationContext#initPropertySources() * @see org.springframework.web.context.support.StandardServletEnvironment * @see org.springframework.web.context.support.ServletContextPropertySource */public static class StubPropertySource extends PropertySource<Object> {public StubPropertySource(String name) {super(name, new Object());}/** * Always return {@code null}. */@Overridepublic String getProperty(String name) {return null;}}/** * @see PropertySource#named(String) */static class ComparisonPropertySource extends StubPropertySource {private static final String USAGE_ERROR ="ComparisonPropertySource instances are for collection comparison " +"use only";public ComparisonPropertySource(String name) {super(name);}@Overridepublic Object getSource() {throw new UnsupportedOperationException(USAGE_ERROR);}@Overridepublic boolean containsProperty(String name) {throw new UnsupportedOperationException(USAGE_ERROR);}@Overridepublic String getProperty(String name) {throw new UnsupportedOperationException(USAGE_ERROR);}@Overridepublic String toString() {return String.format("%s [name='%s']", getClass().getSimpleName(), this.name);}}}
里面有俩内部类,对于不用情况的应用的,这个就是最小的单位了,但是一个系统中会有好多的键值对儿数据,所以基于这个最小元素的接合来了:

PropertySources表示PropertySource集合。

package org.springframework.core.env;/** * Holder containing one or more {@link PropertySource} objects. * * @author Chris Beams * @since 3.1 */public interface PropertySources extends Iterable<PropertySource<?>> {/** * Return whether a property source with the given name is contained. * @param name the {@linkplain PropertySource#getName() name of the property source} to find */boolean contains(String name);/** * Return the property source with the given name, {@code null} if not found. * @param name the {@linkplain PropertySource#getName() name of the property source} to find */PropertySource<?> get(String name);}



所以以后的操作都是围绕这他的家族进行的


下面拿核心类进行开刀,

他有一个数据源

private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);
(这个系统初始化赋值给他一个收集好的数据源)

还有一个

private final ConfigurablePropertyResolver propertyResolver =new PropertySourcesPropertyResolver(this.propertySources);

(对PropertySource的value进行类型转换用的,很重要!)

这个家族体系

这个类型转换具体是由

ConfigurableConversionService

这个体系去完成的

这个体系具体是里面包含了很多的Converter实现类,每个实现类都引用一个

@Overridepublic String getProperty(String key, String defaultValue) {   return this.propertyResolver.getProperty(key, defaultValue);}@Overridepublic <T> T getProperty(String key, Class<T> targetType) {   return this.propertyResolver.getProperty(key, targetType);}
其他一切方法的实现都是去操作的propertyResolver。
0 0