您的位置:首页 > 编程语言 > Java开发

Spring的Envrionment 机制

2015-12-10 17:59 661 查看
摘要: spring提供了普通解构通用的环境机制,可以使用默认或者自定义的环境去配置一些变量或者设置,便于正式运行的环境跟开发,测试的环境分开



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(),持有一个[b]ConfigurableConversionService对象,可以在资源对象的类型转换时候调用,实现自己的逻辑[/b]

/*
* Copyright 2002-2012 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.core.env;

import java.util.Map;

/**
* Configuration interface to be implemented by most if not all {@link Environment} types.
* Provides facilities for setting active and default profiles and manipulating underlying
* property sources. Allows clients to set and validate required properties, customize the
* conversion service and more through the {@link ConfigurablePropertyResolver}
* superinterface.
*
* <h2>Manipulating property sources</h2>
* <p>Property sources may be removed, reordered, or replaced; and additional
* property sources may be added using the {@link MutablePropertySources}
* instance returned from {@link #getPropertySources()}. The following examples
* are against the {@link StandardEnvironment} implementation of
* {@code ConfigurableEnvironment}, but are generally applicable to any implementation,
* though particular default property sources may differ.
*
* <h4>Example: adding a new property source with highest search priority</h4>
* <pre class="code">
*   ConfigurableEnvironment environment = new StandardEnvironment();
*   MutablePropertySources propertySources = environment.getPropertySources();
*   Map<String, String> myMap = new HashMap<String, String>();
*   myMap.put("xyz", "myValue");
*   propertySources.addFirst(new MapPropertySource("MY_MAP", myMap));
* </pre>
*
* <h4>Example: removing the default system properties property source</h4>
* <pre class="code">
*   MutablePropertySources propertySources = environment.getPropertySources();
*   propertySources.remove(StandardEnvironment.SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME)
* </pre>
*
* <h4>Example: mocking the system environment for testing purposes</h4>
* <pre class="code">
*   MutablePropertySources propertySources = environment.getPropertySources();
*   MockPropertySource mockEnvVars = new MockPropertySource().withProperty("xyz", "myValue");
*   propertySources.replace(StandardEnvironment.SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, mockEnvVars);
* </pre>
*
* When an {@link Environment} is being used by an {@code ApplicationContext}, it is
* important that any such {@code PropertySource} manipulations be performed
* <em>before</em> the context's {@link
* org.springframework.context.support.AbstractApplicationContext#refresh() refresh()}
* method is called. This ensures that all property sources are available during the
* container bootstrap process, including use by {@linkplain
* org.springframework.context.support.PropertySourcesPlaceholderConfigurer property
* placeholder configurers}.
*
*
* @author Chris Beams
* @since 3.1
* @see StandardEnvironment
* @see org.springframework.context.ConfigurableApplicationContext#getEnvironment
*/
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {

/**
* Specify the set of profiles active for this {@code Environment}. Profiles are
* evaluated during container bootstrap to determine whether bean definitions
* should be registered with the container.
* <p>Any existing active profiles will be replaced with the given arguments; call
* with zero arguments to clear the current set of active profiles. Use
* {@link #addActiveProfile} to add a profile while preserving the existing set.
* @see #addActiveProfile
* @see #setDefaultProfiles
* @see org.springframework.context.annotation.Profile
* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
* @throws IllegalArgumentException if any profile is null, empty or whitespace-only
*/
void setActiveProfiles(String... profiles);

/**
* Add a profile to the current set of active profiles.
* @see #setActiveProfiles
* @throws IllegalArgumentException if the profile is null, empty or whitespace-only
*/
void addActiveProfile(String profile);

/**
* Specify the set of profiles to be made active by default if no other profiles
* are explicitly made active through {@link #setActiveProfiles}.
* @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME
* @throws IllegalArgumentException if any profile is null, empty or whitespace-only
*/
void setDefaultProfiles(String... profiles);

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

/**
* Return the value of {@link System#getenv()} if allowed by the current
* {@link SecurityManager}, otherwise return a map implementation that will attempt
* to access individual keys using calls to {@link System#getenv(String)}.
* <p>Note that most {@link Environment} implementations will include this system
* environment map as a default {@link PropertySource} to be searched. Therefore, it
* is recommended that this method not be used directly unless bypassing other
* property sources is expressly intended.
* <p>Calls to {@link Map#get(Object)} on the Map returned will never throw
* {@link IllegalAccessException}; in cases where the SecurityManager forbids access
* to a property, {@code null} will be returned and an INFO-level log message will be
* issued noting the exception.
*/
Map<String, Object> getSystemEnvironment();

/**
* Return the value of {@link System#getProperties()} if allowed by the current
* {@link SecurityManager}, otherwise return a map implementation that will attempt
* to access individual keys using calls to {@link System#getProperty(String)}.
* <p>Note that most {@code Environment} implementations will include this system
* properties map as a default {@link PropertySource} to be searched. Therefore, it is
* recommended that this method not be used directly unless bypassing other property
* sources is expressly intended.
* <p>Calls to {@link Map#get(Object)} on the Map returned will never throw
* {@link IllegalAccessException}; in cases where the SecurityManager forbids access
* to a property, {@code null} will be returned and an INFO-level log message will be
* issued noting the exception.
*/
Map<String, Object> getSystemProperties();

/**
* Append the given parent environment's active profiles, default profiles and
* property sources to this (child) environment's respective collections of each.
* <p>For any identically-named {@code PropertySource} instance existing in both
* parent and child, the child instance is to be preserved and the parent instance
* discarded. This has the effect of allowing overriding of property sources by the
* child as well as avoiding redundant searches through common property source types,
* e.g. system environment and system properties.
* <p>Active and default profile names are also filtered for duplicates, to avoid
* confusion and redundant storage.
* <p>The parent environment remains unmodified in any case. Note that any changes to
* the parent environment occurring after the call to {@code merge} will not be
* reflected in the child. Therefore, care should be taken to configure parent
* property sources and profile information prior to calling {@code merge}.
* @param parent the environment to merge with
* @since 3.1.2
* @see org.springframework.context.support.AbstractApplicationContext#setParent
*/
void merge(ConfigurableEnvironment parent);

}

其中ConfigurablePropertyResolver:这个对象是操作converting property values from one type to another

/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.core.env;

import org.springframework.core.convert.support.ConfigurableConversionService;

/**
* Configuration interface to be implemented by most if not all {@link PropertyResolver
* PropertyResolver} types. Provides facilities for accessing and customizing the
* {@link org.springframework.core.convert.ConversionService ConversionService} used when
* converting property values from one type to another.
*
* @author Chris Beams
* @since 3.1
*/
public interface ConfigurablePropertyResolver extends PropertyResolver {

/**
* @return the {@link ConfigurableConversionService} used when performing type
* conversions on properties.
* <p>The configurable nature of the returned conversion service allows for
* the convenient addition and removal of individual {@code Converter} instances:
* <pre class="code">
* ConfigurableConversionService cs = env.getConversionService();
* cs.addConverter(new FooConverter());
* </pre>
* @see PropertyResolver#getProperty(String, Class)
* @see org.springframework.core.convert.converter.ConverterRegistry#addConverter
*/
ConfigurableConversionService getConversionService();

/**
* Set the {@link ConfigurableConversionService} to be used when performing type
* conversions on properties.
* <p><strong>Note:</strong> as an alternative to fully replacing the {@code
* ConversionService}, consider adding or removing individual {@code Converter}
* instances by drilling into {@link #getConversionService()} and calling methods
* such as {@code #addConverter}.
* @see PropertyResolver#getProperty(String, Class)
* @see #getConversionService()
* @see org.springframework.core.convert.converter.ConverterRegistry#addConverter
*/
void setConversionService(ConfigurableConversionService conversionService);

/**
* Set the prefix that placeholders replaced by this resolver must begin with.
*/
void setPlaceholderPrefix(String placeholderPrefix);

/**
* Set the suffix that placeholders replaced by this resolver must end with.
*/
void setPlaceholderSuffix(String placeholderSuffix);

/**
* Specify the separating character between the placeholders replaced by this
* resolver and their associated default value, or {@code null} if no such
* special character should be processed as a value separator.
*/
void setValueSeparator(String valueSeparator);

/**
* Set whether to throw an exception when encountering an unresolvable placeholder
* nested within the value of a given property. A {@code false} value indicates strict
* resolution, i.e. that an exception will be thrown. A {@code true} value indicates
* that unresolvable nested placeholders should be passed through in their unresolved
* ${...} form.
* <p>Implementations of {@link #getProperty(String)} and its variants must inspect
* the value set here to determine correct behavior when property values contain
* unresolvable placeholders.
* @since 3.2
*/
void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);

/**
* Specify which properties must be present, to be verified by
* {@link #validateRequiredProperties()}.
*/
void setRequiredProperties(String... requiredProperties);

/**
* Validate that each of the properties specified by
* {@link #setRequiredProperties} is present and resolves to a
* non-{@code null} value.
* @throws MissingRequiredPropertiesException if any of the required
* properties are not resolvable.
*/
void validateRequiredProperties() throws MissingRequiredPropertiesException;

}


第四层为AbstractEnvironment 可以接收自定义的profile,设置默认的profile,有个customizePropertySources(MutablePropertySources)方法需要子类实现的,设置数据源

/*
* Copyright 2002-2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.springframework.core.env;

import java.security.AccessControlException;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.SpringProperties;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import static java.lang.String.*;
import static org.springframework.util.StringUtils.*;

/**
* Abstract base class for {@link Environment} implementations. Supports the notion of
* reserved default profile names and enables specifying active and default profiles
* through the {@link #ACTIVE_PROFILES_PROPERTY_NAME} and
* {@link #DEFAULT_PROFILES_PROPERTY_NAME} properties.
*
* <p>Concrete subclasses differ primarily on which {@link PropertySource} objects they
* add by default. {@code AbstractEnvironment} adds none. Subclasses should contribute
* property sources through the protected {@link #customizePropertySources(MutablePropertySources)}
* hook, while clients should customize using {@link ConfigurableEnvironment#getPropertySources()}
* and working against the {@link MutablePropertySources} API.
* See {@link ConfigurableEnvironment} javadoc for usage examples.
*
* @author Chris Beams
* @author Juergen Hoeller
* @since 3.1
* @see ConfigurableEnvironment
* @see StandardEnvironment
*/
public abstract class AbstractEnvironment implements ConfigurableEnvironment {

/**
* System property that instructs Spring to ignore system environment variables,
* i.e. to never attempt to retrieve such a variable via {@link System#getenv()}.
* <p>The default is "false", falling back to system environment variable checks if a
* Spring environment property (e.g. a placeholder in a configuration String) isn't
* resolvable otherwise. Consider switching this flag to "true" if you experience
* log warnings from {@code getenv} calls coming from Spring, e.g. on WebSphere
* with strict SecurityManager settings and AccessControlExceptions warnings.
* @see #suppressGetenvAccess()
*/
public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";

/**
* Name of property to set to specify active profiles: {@value}. Value may be comma
* delimited.
* <p>Note that certain shell environments such as Bash disallow the use of the period
* character in variable names. Assuming that Spring's {@link SystemEnvironmentPropertySource}
* is in use, this property may be specified as an environment variable as
* {@code SPRING_PROFILES_ACTIVE}.
* @see ConfigurableEnvironment#setActiveProfiles
*/
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";

/**
* Name of property to set to specify profiles active by default: {@value}. Value may
* be comma delimited.
* <p>Note that certain shell environments such as Bash disallow the use of the period
* character in variable names. Assuming that Spring's {@link SystemEnvironmentPropertySource}
* is in use, this property may be specified as an environment variable as
* {@code SPRING_PROFILES_DEFAULT}.
* @see ConfigurableEnvironment#setDefaultProfiles
*/
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";

/**
* Name of reserved default profile name: {@value}. If no default profile names are
* explicitly and no active profile names are explicitly set, this profile will
* automatically be activated by default.
* @see #getReservedDefaultProfiles
* @see ConfigurableEnvironment#setDefaultProfiles
* @see ConfigurableEnvironment#setActiveProfiles
* @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME
* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME
*/
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";

protected final Log logger = LogFactory.getLog(getClass());

private Set<String> activeProfiles = new LinkedHashSet<String>();

private Set<String> defaultProfiles = new LinkedHashSet<String>(getReservedDefaultProfiles());

private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);

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

/**
* Create a new {@code Environment} instance, calling back to
* {@link #customizePropertySources(MutablePropertySources)} during construction to
* allow subclasses to contribute or manipulate {@link PropertySource} instances as
* appropriate.
* @see #customizePropertySources(MutablePropertySources)
*/
public AbstractEnvironment() {
customizePropertySources(this.propertySources);
if (this.logger.isDebugEnabled()) {
this.logger.debug(format(
"Initialized %s with PropertySources %s", getClass().getSimpleName(), this.propertySources));
}
}

/**
* Customize the set of {@link PropertySource} objects to be searched by this
* {@code Environment} during calls to {@link #getProperty(String)} and related
* methods.
*
* <p>Subclasses that override this method are encouraged to add property
* sources using {@link MutablePropertySources#addLast(PropertySource)} such that
* further subclasses may call {@code super.customizePropertySources()} with
* predictable results. For example:
* <pre class="code">
* public class Level1Environment extends AbstractEnvironment {
*     @Override
*     protected void customizePropertySources(MutablePropertySources propertySources) {
*         super.customizePropertySources(propertySources); // no-op from base class
*         propertySources.addLast(new PropertySourceA(...));
*         propertySources.addLast(new PropertySourceB(...));
*     }
* }
*
* public class Level2Environment extends Level1Environment {
*     @Override
*     protected void customizePropertySources(MutablePropertySources propertySources) {
*         super.customizePropertySources(propertySources); // add all from superclass
*         propertySources.addLast(new PropertySourceC(...));
*         propertySources.addLast(new PropertySourceD(...));
*     }
* }
* </pre>
* In this arrangement, properties will be resolved against sources A, B, C, D in that
* order. That is to say that property source "A" has precedence over property source
* "D". If the {@code Level2Environment} subclass wished to give property sources C
* and D higher precedence than A and B, it could simply call
* {@code super.customizePropertySources} after, rather than before adding its own:
* <pre class="code">
* public class Level2Environment extends Level1Environment {
*     @Override
*     protected void customizePropertySources(MutablePropertySources propertySources) {
*         propertySources.addLast(new PropertySourceC(...));
*         propertySources.addLast(new PropertySourceD(...));
*         super.customizePropertySources(propertySources); // add all from superclass
*     }
* }
* </pre>
* The search order is now C, D, A, B as desired.
*
* <p>Beyond these recommendations, subclasses may use any of the {@code add*},
* {@code remove}, or {@code replace} methods exposed by {@link MutablePropertySources}
* in order to create the exact arrangement of property sources desired.
*
* <p>The base implementation registers no property sources.
*
* <p>Note that clients of any {@link ConfigurableEnvironment} may further customize
* property sources via the {@link #getPropertySources()} accessor, typically within
* an {@link org.springframework.context.ApplicationContextInitializer
* ApplicationContextInitializer}. For example:
* <pre class="code">
* ConfigurableEnvironment env = new StandardEnvironment();
* env.getPropertySources().addLast(new PropertySourceX(...));
* </pre>
*
* <h2>A warning about instance variable access</h2>
* Instance variables declared in subclasses and having default initial values should
* <em>not</em> be accessed from within this method. Due to Java object creation
* lifecycle constraints, any initial value will not yet be assigned when this
* callback is invoked by the {@link #AbstractEnvironment()} constructor, which may
* lead to a {@code NullPointerException} or other problems. If you need to access
* default values of instance variables, leave this method as a no-op and perform
* property source manipulation and instance variable access directly within the
* subclass constructor. Note that <em>assigning</em> values to instance variables is
* not problematic; it is only attempting to read default values that must be avoided.
*
* @see MutablePropertySources
* @see PropertySourcesPropertyResolver
* @see org.springframework.context.ApplicationContextInitializer
*/
protected void customizePropertySources(MutablePropertySources propertySources) {
}

/**
* Return the set of reserved default profile names. This implementation returns
* {@value #RESERVED_DEFAULT_PROFILE_NAME}. Subclasses may override in order to
* customize the set of reserved names.
* @see #RESERVED_DEFAULT_PROFILE_NAME
* @see #doGetDefaultProfiles()
*/
protected Set<String> getReservedDefaultProfiles() {
return Collections.singleton(RESERVED_DEFAULT_PROFILE_NAME);
}

//---------------------------------------------------------------------
// Implementation of ConfigurableEnvironment interface
//---------------------------------------------------------------------

@Override
public String[] getActiveProfiles() {
return StringUtils.toStringArray(doGetActiveProfiles());
}

/**
* Return the set of active profiles as explicitly set through
* {@link #setActiveProfiles} or if the current set of active profiles
* is empty, check for the presence of the {@value #ACTIVE_PROFILES_PROPERTY_NAME}
* property and assign its value to the set of active profiles.
* @see #getActiveProfiles()
* @see #ACTIVE_PROFILES_PROPERTY_NAME
*/
protected Set<String> doGetActiveProfiles() {
if (this.activeProfiles.isEmpty()) {
String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
if (StringUtils.hasText(profiles)) {
setActiveProfiles(commaDelimitedListToStringArray(trimAllWhitespace(profiles)));
}
}
return this.activeProfiles;
}

@Override
public void setActiveProfiles(String... profiles) {
Assert.notNull(profiles, "Profile array must not be null");
this.activeProfiles.clear();
for (String profile : profiles) {
validateProfile(profile);
this.activeProfiles.add(profile);
}
}

@Override
public void addActiveProfile(String profile) {
if (this.logger.isDebugEnabled()) {
this.logger.debug(format("Activating profile '%s'", profile));
}
validateProfile(profile);
doGetActiveProfiles();
this.activeProfiles.add(profile);
}

@Override
public String[] getDefaultProfiles() {
return StringUtils.toStringArray(doGetDefaultProfiles());
}

/**
* Return the set of default profiles explicitly set via
* {@link #setDefaultProfiles(String...)} or if the current set of default profiles
* consists only of {@linkplain #getReservedDefaultProfiles() reserved default
* profiles}, then check for the presence of the
* {@value #DEFAULT_PROFILES_PROPERTY_NAME} property and assign its value (if any)
* to the set of default profiles.
* @see #AbstractEnvironment()
* @see #getDefaultProfiles()
* @see #DEFAULT_PROFILES_PROPERTY_NAME
* @see #getReservedDefaultProfiles()
*/
protected Set<String> doGetDefaultProfiles() {
if (this.defaultProfiles.equals(getReservedDefaultProfiles())) {
String profiles = getProperty(DEFAULT_PROFILES_PROPERTY_NAME);
if (StringUtils.hasText(profiles)) {
setDefaultProfiles(commaDelimitedListToStringArray(trimAllWhitespace(profiles)));
}
}
return this.defaultProfiles;
}

/**
* Specify the set of profiles to be made active by default if no other profiles
* are explicitly made active through {@link #setActiveProfiles}.
* <p>Calling this method removes overrides any reserved default profiles
* that may have been added during construction of the environment.
* @see #AbstractEnvironment()
* @see #getReservedDefaultProfiles()
*/
@Override
public void setDefaultProfiles(String... profiles) {
Assert.notNull(profiles, "Profile array must not be null");
this.defaultProfiles.clear();
for (String profile : profiles) {
validateProfile(profile);
this.defaultProfiles.add(profile);
}
}

@Override
public boolean acceptsProfiles(String... profiles) {
Assert.notEmpty(profiles, "Must specify at least one profile");
for (String profile : profiles) {
if (profile != null && profile.length() > 0 && profile.charAt(0) == '!') {
if (!isProfileActive(profile.substring(1))) {
return true;
}
}
else if (isProfileActive(profile)) {
return true;
}
}
return false;
}

/**
* Return whether the given profile is active, or if active profiles are empty
* whether the profile should be active by default.
* @throws IllegalArgumentException per {@link #validateProfile(String)}
*/
protected boolean isProfileActive(String profile) {
validateProfile(profile);
return doGetActiveProfiles().contains(profile) ||
(doGetActiveProfiles().isEmpty() && doGetDefaultProfiles().contains(profile));
}

/**
* Validate the given profile, called internally prior to adding to the set of
* active or default profiles.
* <p>Subclasses may override to impose further restrictions on profile syntax.
* @throws IllegalArgumentException if the profile is null, empty, whitespace-only or
* begins with the profile NOT operator (!).
* @see #acceptsProfiles
* @see #addActiveProfile
* @see #setDefaultProfiles
*/
protected void validateProfile(String profile) {
if (!StringUtils.hasText(profile)) {
throw new IllegalArgumentException("Invalid profile [" + profile + "]: must contain text");
}
if (profile.charAt(0) == '!') {
throw new IllegalArgumentException("Invalid profile [" + profile + "]: must not begin with ! operator");
}
}

@Override
public MutablePropertySources getPropertySources() {
return this.propertySources;
}

@Override
@SuppressWarnings("unchecked")
public Map<String, Object> getSystemEnvironment() {
if (suppressGetenvAccess()) {
return Collections.emptyMap();
}
try {
return (Map) System.getenv();
}
catch (AccessControlException ex) {
return (Map) new ReadOnlySystemAttributesMap() {
@Override
protected String getSystemAttribute(String attributeName) {
try {
return System.getenv(attributeName);
}
catch (AccessControlException ex) {
if (logger.isInfoEnabled()) {
logger.info(format("Caught AccessControlException when accessing system " +
"environment variable [%s]; its value will be returned [null]. Reason: %s",
attributeName, ex.getMessage()));
}
return null;
}
}
};
}
}

/**
* Determine whether to suppress {@link System#getenv()}/{@link System#getenv(String)}
* access for the purposes of {@link #getSystemEnvironment()}.
* <p>If this method returns {@code true}, an empty dummy Map will be used instead
* of the regular system environment Map, never even trying to call {@code getenv}
* and therefore avoiding security manager warnings (if any).
* <p>The default implementation checks for the "spring.getenv.ignore" system property,
* returning {@code true} if its value equals "true" in any case.
* @see #IGNORE_GETENV_PROPERTY_NAME
* @see SpringProperties#getFlag
*/
protected boolean suppressGetenvAccess() {
return SpringProperties.getFlag(IGNORE_GETENV_PROPERTY_NAME);
}

@Override
@SuppressWarnings("unchecked")
public Map<String, Object> getSystemProperties() {
try {
return (Map) System.getProperties();
}
catch (AccessControlException ex) {
return (Map) new ReadOnlySystemAttributesMap() {
@Override
protected String getSystemAttribute(String attributeName) {
try {
return System.getProperty(attributeName);
}
catch (AccessControlException ex) {
if (logger.isInfoEnabled()) {
logger.info(format("Caught AccessControlException when accessing system " +
"property [%s]; its value will be returned [null]. Reason: %s",
attributeName, ex.getMessage()));
}
return null;
}
}
};
}
}

@Override
public void merge(ConfigurableEnvironment parent) {
for (PropertySource<?> ps : parent.getPropertySources()) {
if (!this.propertySources.contains(ps.getName())) {
this.propertySources.addLast(ps);
}
}
for (String profile : parent.getActiveProfiles()) {
this.activeProfiles.add(profile);
}
if (parent.getDefaultProfiles().length > 0) {
this.defaultProfiles.remove(RESERVED_DEFAULT_PROFILE_NAME);
for (String profile : parent.getDefaultProfiles()) {
this.defaultProfiles.add(profile);
}
}
}

//---------------------------------------------------------------------
// Implementation of ConfigurablePropertyResolver interface
//---------------------------------------------------------------------

@Override
public ConfigurableConversionService getConversionService() {
return this.propertyResolver.getConversionService();
}

@Override
public void setConversionService(ConfigurableConversionService conversionService) {
this.propertyResolver.setConversionService(conversionService);
}

@Override
public void setPlaceholderPrefix(String placeholderPrefix) {
this.propertyResolver.setPlaceholderPrefix(placeholderPrefix);
}

@Override
public void setPlaceholderSuffix(String placeholderSuffix) {
this.propertyResolver.setPlaceholderSuffix(placeholderSuffix);
}

@Override
public void setValueSeparator(String valueSeparator) {
this.propertyResolver.setValueSeparator(valueSeparator);
}

@Override
public void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders) {
this.propertyResolver.setIgnoreUnresolvableNestedPlaceholders(ignoreUnresolvableNestedPlaceholders);
}

@Override
public void setRequiredProperties(String... requiredProperties) {
this.propertyResolver.setRequiredProperties(requiredProperties);
}

@Override
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
this.propertyResolver.validateRequiredProperties();
}

//---------------------------------------------------------------------
// Implementation of PropertyResolver interface
//---------------------------------------------------------------------

@Override
public boolean containsProperty(String key) {
return this.propertyResolver.containsProperty(key);
}

@Override
public String getProperty(String key) {
return this.propertyResolver.getProperty(key);
}

@Override
public String getProperty(String key, String defaultValue) {
return this.propertyResolver.getProperty(key, defaultValue);
}

@Override
public <T> T getProperty(String key, Class<T> targetType) {
return this.propertyResolver.getProperty(key, targetType);
}

@Override
public <T> T getProperty(String key, Class<T> targetType, T defaultValue) {
return this.propertyResolver.getProperty(key, targetType, defaultValue);
}

@Override
public <T> Class<T> getPropertyAsClass(String key, Class<T> targetType) {
return this.propertyResolver.getPropertyAsClass(key, targetType);
}

@Override
public String getRequiredProperty(String key) throws IllegalStateException {
return this.propertyResolver.getRequiredProperty(key);
}

@Override
public <T> T getRequiredProperty(String key, Class<T> targetType) throws IllegalStateException {
return this.propertyResolver.getRequiredProperty(key, targetType);
}

@Override
public String resolvePlaceholders(String text) {
return this.propertyResolver.resolvePlaceholders(text);
}

@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
return this.propertyResolver.resolveRequiredPlaceholders(text);
}

@Override
public String toString() {
return format("%s {activeProfiles=%s, defaultProfiles=%s, propertySources=%s}",
getClass().getSimpleName(), this.activeProfiles, this.defaultProfiles,
this.propertySources);
}

}


底层子类StandardEnvironment

/*
* Copyright 2002-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0 *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.env;
/**
* {@link Environment} implementation suitable for use in 'standard' (i.e. non-web)
* applications.
*
* <p>In addition to the usual functions of a {@link ConfigurableEnvironment} such as
* property resolution and profile-related operations, this implementation configures two
* default property sources, to be searched in the following order:
* <ul>
* <li>{@linkplain AbstractEnvironment#getSystemProperties() system properties}
* <li>{@linkplain AbstractEnvironment#getSystemEnvironment() system environment variables}
* </ul>
*
* That is, if the key "xyz" is present both in the JVM system properties as well as in
* the set of environment variables for the current process, the value of key "xyz" from
* system properties will return from a call to {@code environment.getProperty("xyz")}.
* This ordering is chosen by default because system properties are per-JVM, while
* environment variables may be the same across many JVMs on a given system.  Giving
* system properties precedence allows for overriding of environment variables on a
* per-JVM basis.
*
* <p>These default property sources may be removed, reordered, or replaced; and
* additional property sources may be added using the {@link MutablePropertySources}
* instance available from {@link #getPropertySources()}. See
* {@link ConfigurableEnvironment} Javadoc for usage examples.
*
* <p>See {@link SystemEnvironmentPropertySource} javadoc for details on special handling
* of property names in shell environments (e.g. Bash) that disallow period characters in
* variable names.
*
* @author Chris Beams
* @since 3.1
* @see ConfigurableEnvironment
* @see SystemEnvironmentPropertySource
* @see org.springframework.web.context.support.StandardServletEnvironment
*/
public class StandardEnvironment extends AbstractEnvironment {
/** System environment property source name: {@value} */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value} */
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";
/**
* Customize the set of property sources with those appropriate for any standard
* Java environment:
* <ul>
* <li>{@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME}
* <li>{@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}
* </ul>
* <p>Properties present in {@value #SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME} will
* take precedence over those in {@value #SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME}.
* @see AbstractEnvironment#customizePropertySources(MutablePropertySources)
* @see #getSystemProperties()
* @see #getSystemEnvironment()
*/
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new MapPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}
}


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

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

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



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

/*
* 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.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;

/**
* 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(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 this.source;
}

/**
* Return whether this {@code PropertySource} contains the given name.
* <p>This implementation simply checks for a {@code 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 (getProperty(name) != null);
}

/**
* Return the value associated with the given name,
* or {@code null} if not found.
* @param name the property to find
* @see PropertyResolver#getRequiredProperty(String)
*/
public abstract Object getProperty(String name);

/**
* 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.
*/
@Override
public boolean equals(Object obj) {
return (this == obj || (obj instanceof PropertySource &&
ObjectUtils.nullSafeEquals(this.name, ((PropertySource<?>) obj).name)));
}

/**
* Return a hash code derived from the {@code name} property
* of this {@code PropertySource} object.
*/
@Override
public int hashCode() {
return ObjectUtils.nullSafeHashCode(this.name);
}

/**
* Produce concise output (type and name) if the current log level does not include
* debug. If debug is enabled, produce verbose output including the hash code of the
* PropertySource instance and every name/value property pair.
* <p>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()
*/
@Override
public String toString() {
if (logger.isDebugEnabled()) {
return String.format("%s@%s [name='%s', properties=%s]",
getClass().getSimpleName(), System.identityHashCode(this), this.name, this.source);
}
else {
return String.format("%s [name='%s']", 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 returns {@code null}.
*/
@Override
public 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 use with collection comparison only";

public ComparisonPropertySource(String name) {
super(name);
}

@Override
public Object getSource() {
throw new UnsupportedOperationException(USAGE_ERROR);
}

@Override
public boolean containsProperty(String name) {
throw new UnsupportedOperationException(USAGE_ERROR);
}

@Override
public String getProperty(String name) {
throw new UnsupportedOperationException(USAGE_ERROR);
}

@Override
public String toString() {
return String.format("%s [name='%s']", getClass().getSimpleName(), this.name);
}
}

}

里面有俩内部类,对于不用情况的应用的,这个就是最小的单位了,但是一个系统中会有好多的键值对儿数据,所以基于这个最小元素的接合来了:

/*
* Copyright 2002-2011 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;

/**
* 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);

}

PropertySources 这个是一个PropertySource的集合体哦,(多了个"s")

看看这个集合的家族体系



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

下面拿核心类进行开刀,



他有一个数据源

private final MutablePropertySources propertySources = new MutablePropertySources(this.logger);

(这个系统初始化赋值给他一个收集好的数据源)

还有一个

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

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

这个家族体系



这个类型转换具体是由

ConfigurableConversionService

这个体系去完成的

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

@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);
}

其他一切方法的实现都是去操作的propertyResolver
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java spring