码迷,mamicode.com
首页 > 编程语言 > 详细

Spring的Envrionment 机制

时间:2015-04-28 16:23:48      阅读:502      评论:0      收藏:0      [点我收藏+]

标签:


技术分享


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 {
    *     &#064;Override
    *     protected void customizePropertySources(MutablePropertySources propertySources) {
    *         super.customizePropertySources(propertySources); // no-op from base class
    *         propertySources.addLast(new PropertySourceA(...));
    *         propertySources.addLast(new PropertySourceB(...));
    *     }
    * }
    *
    * public class Level2Environment extends Level1Environment {
    *     &#064;Override
    *     protected void customizePropertySources(MutablePropertySources propertySources) {
    *         super.customizePropertySources(propertySources); // add all from superclass
    *         propertySources.addLast(new PropertySourceC(...));
    *         propertySources.addLast(new PropertySourceD(...));
    *     }
    * }
    * </pre>
    * In this arrangement, properties will be resolved against sources A, B, C, D in that
    * order. That is to say that property source "A" has precedence over property source
    * "D". If the {@code Level2Environment} subclass wished to give property sources C
    * and D higher precedence than A and B, it could simply call
    * {@code super.customizePropertySources} after, rather than before adding its own:
    * <pre class="code">
    * public class Level2Environment extends Level1Environment {
    *     &#064;Override
    *     protected void customizePropertySources(MutablePropertySources propertySources) {
    *         propertySources.addLast(new PropertySourceC(...));
    *         propertySources.addLast(new PropertySourceD(...));
    *         super.customizePropertySources(propertySources); // add all from superclass
    *     }
    * }
    * </pre>
    * The search order is now C, D, A, B as desired.
    *
    * <p>Beyond these recommendations, subclasses may use any of the {@code add&#42;},
    * {@code 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()));
    }
}


Spring的Envrionment 机制

标签:

原文地址:http://my.oschina.net/u/867830/blog/407191

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!