Spring Environment抽象
1:概述
Spring中Environment是Spring3.1版本引入的,是Spring核心框架定义的一个接口,用来表示整个应用运行时环境。该环境模型只接受两种应用环境profiles(配置文件)和properties(属性)。与属性访问相关的方法通过PropertyResolver超接口访问。
建模关键
profile(配置文件)
一个
profile是一组Bean定义的逻辑分组,只有当配置文件被激活的时候,才会将对应逻辑上组织的Bean定义注册到容器中。Bean添加到profile可以通过XML或者Annotation方式。Environment对象对于profile机制所扮演的角色是用来指定哪些profile是当前活跃或者缺省活跃。可以通过getActiveProfiles或者getDefaultProfiles获取。
proprety(属性)
一个应用属性有很多来源:属性文件(properties files),JVM系统属性(
getSystemProperties),系统变量属性(getSystemEnvironment),JNDI,servlet上下文参数,临时属性对象,Maps等。Environment对于property所扮演的角色提供给使用一个方便服务接口用于配置属性源
从属性源解析和获取属性
容器上下文(ApplicationContext)所获取的bean,如果想直接使用Environment对象访问profile状态或者获取属性。有以下方式。
EnvironmentAware接口@Inject或者@Autowired注入一个Environment对象
绝大多数情况,bean都不需要直接访问Environment对象,而是通过类似@Value注解方式把属性值注入进来。
这个接口定义在包 org.springframework.core.env 中。下面是Spring围绕环境抽象Environment各个接口/类之间的继承关系:

2:Environment接口相关类介绍
| 接口|类 | 介绍 |
|---|---|
PropertyResolver |
接口,抽象对属性源的访问比如是否包含某个属性,读取属性,解析占位符,将读取到的属性转换成指定类型 (提供读操作)默认实现PropertySourcesPropertyResolver |
Environment |
接口,继承自PropertyResolver,对环境属性访问和default/active profile访问的抽象 。 |
ConfigurablePropertyResolver |
接口,为PropertyResolver接口抽象的属性源访问做了配置方面的增强。(提供写操作。) |
ConfigurableEnvironment |
接口,在所继承的接口之上增加了设置defaut/active profile的能力,增加/删除环境对象中属性源的能力 |
ConfigurableWebEnvironment |
接口,向接口ConfigurableEnvironment增强了根据Servlet上下文/配置初始化属性源的能力 |
AbstractEnvironment |
Environment抽象基类,实现了ConfigurableEnvironment |
StandardEnvironment |
实现类,针对标准Spring应用(非Web应用)环境, 在AbstractEnvironment基础上提供了属性源systemEnvironment(来自System.getenv())和systemProperties(来自System.getProperties()) |
StandardServletEnvironment |
实现类,针对标准Spring Servlet Web应用的环境, 增加了servletContextInitParams/servletConfigInitParams/jndiProperties |
3:外部化配置抽象相关类
| 接口|类 | 介绍 |
|---|---|
PropertySource |
用来抽象属性键值对(外部化配置,即属性源)配置基类。例如Map,Properties,ServletConfig,ServletContext |
PropertySources |
对PropertySource抽象属性键值对外部化配置提供集合操作。 |
MutablePropertySources |
PropertySources默认实现。 |
MapPropertySource |
Map对象中读取属性键值对 |
PropertiesPropertySource |
Properties对象中读取属性键值对 |
ResourcePropertySource |
Resource对象读取中读取属性键值对。只支持.xml和.properties文件。底层实现使用了工具类PropertiesLoaderUtils。 |
CompositePropertySource |
聚合一组PropertySource。 |
| Web环境实现类和JNDI实现类和随机数实现类 | ServletConfigPropertySource,ServletContextPropertySource, JndiPropertySource,RandomValuePropertySource |
| 命令行参数实现类 | CommandLinePropertySource |
4:混淆定义
上下文:用来处理分层传递抽象,代表着
应用。环境:
当前上下文运行环境,存储各种全局变量。比如JDK信息,内存信息等等。
5:核心API
PropertySource:属性源。key-value属性对抽象
PropertyResolver:属性解析器。用于解析相应key的value
Profile:配置。只有激活的配置profile的组件/配置才会注册到Spring容器,类似于maven中profile。
Environment:环境,本身也是个属性解析器
PropertyResolver。
6:属性解析器相关类详细介绍
PropertySourcesPropertyResolver
该类是Spring内建提供的PropertyResolver唯一实现类。环境抽象Environment属性解析委托给该类。包括对属性类型之间必要转换。Converter和ConverterService。实际的占位符解析委托给PropertyPlaceholderHelper。
public class PropertySourcesPropertyResolver extends AbstractPropertyResolver {
...
@Nullable
private final PropertySources propertySources; //内部持有一组PropertySource
// 由此可以看出propertySources的顺序很重要~~~
// 并且还能处理占位符~~~~~ resolveNestedPlaceholders支持内嵌、嵌套占位符
@Nullable
protected <T> T getProperty(String key, Class<T> targetValueType, boolean resolveNestedPlaceholders) {
if (this.propertySources != null) {
for (PropertySource<?> propertySource : this.propertySources) {
Object value = propertySource.getProperty(key);
if (value != null) {
if (resolveNestedPlaceholders && value instanceof String) {
value = resolveNestedPlaceholders((String) value);
}
logKeyFound(key, propertySource, value);
return convertValueIfNecessary(value, targetValueType);
}
}
}
return null;
}
...
}
public abstract class AbstractPropertyResolver implements ConfigurablePropertyResolver {
...
@Nullable
private volatile ConfigurableConversionService conversionService;
@Nullable
private PropertyPlaceholderHelper nonStrictHelper;
@Nullable
private PropertyPlaceholderHelper strictHelper;
private boolean ignoreUnresolvableNestedPlaceholders = false;
private String placeholderPrefix = SystemPropertyUtils.PLACEHOLDER_PREFIX;
private String placeholderSuffix = SystemPropertyUtils.PLACEHOLDER_SUFFIX;
@Nullable
private String valueSeparator = SystemPropertyUtils.VALUE_SEPARATOR;
private final Set<String> requiredProperties = new LinkedHashSet<>();
...
}
7:应用环境抽象Environment
Environment接口:环境的读操作
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:增加环境的写操作
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
// 指定该环境下的 profile 集
void setActiveProfiles(String... profiles);
// 增加此环境的 profile
void addActiveProfile(String profile);
// 设置默认的 profile
void setDefaultProfiles(String... profiles);
// 返回此环境的 PropertySources
MutablePropertySources getPropertySources();
// 尝试返回 System.getenv() 的值,若失败则返回通过 System.getenv(string) 的来访问各个键的映射
Map<String, Object> getSystemEnvironment();
// 尝试返回 System.getProperties() 的值,若失败则返回通过 System.getProperties(string) 的来访问各个键的映射
Map<String, Object> getSystemProperties();
void merge(ConfigurableEnvironment parent);
}
AbstractEnvironment:作为环境接口抽象实现,主要实现了profile相关功能
public abstract class AbstractEnvironment implements ConfigurableEnvironment {
public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
// 请参考:ConfigurableEnvironment#setActiveProfiles
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
// 请参考:ConfigurableEnvironment#setDefaultProfiles
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());
// 默认的profile名称
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";
...
protected Set<String> doGetActiveProfiles() {
synchronized (this.activeProfiles) {
if (this.activeProfiles.isEmpty()) {
String profiles = getProperty(ACTIVE_PROFILES_PROPERTY_NAME);
if (StringUtils.hasText(profiles)) {
setActiveProfiles(StringUtils.commaDelimitedListToStringArray(
StringUtils.trimAllWhitespace(profiles)));
}
}
return this.activeProfiles;
}
}
...
}
如果 activeProfiles 为空,则从 Properties 中获取 spring.profiles.active 配置;如果不为空,则调用 setActiveProfiles() 设置 profile,最后返回。
从这里可以知道,API设置的activeProfiles优先级第一,其次才是属性配置。
8:应用环境配置激活(@Profile和ProfileCondition)
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Conditional(ProfileCondition.class)
public @interface Profile {
String[] value();
}
从Spring4.0开始提供Conditional接口,该注解实现原理基于Condition条件接口,Condition条件接口计算结果实现类为ConditionEvaluator,该类是个内部类。
ProfileCondition
class ProfileCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 因为value值是个数组,所以此处有多个值 用的MultiValueMap
MultiValueMap<String, Object> attrs = metadata.getAllAnnotationAttributes(Profile.class.getName());
if (attrs != null) {
for (Object value : attrs.get("value")) {
// 多个值中,但凡只要有一个acceptsProfiles了,那就返回true~
if (context.getEnvironment().acceptsProfiles(Profiles.of((String[]) value))) {
return true;
}
}
return false;
}
return true;
}
}
@Profile的value可以指定多个值,并且只需要有一个值符合了条件,@Profile标注的方法、类就会生效,就会被加入到容器内。
Spring Environment抽象的更多相关文章
- Spring系列15:Environment抽象
本文内容 Environment抽象的2个重要概念 @Profile 的使用 @PropertySource 的使用 Environment抽象的2个重要概念 Environment 接口表示当前应用 ...
- Spring Environment(一)API 介绍
Spring Environment(一)API 使用 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring 3. ...
- Spring Environment(二)源码分析
Spring Environment(二)源码分析 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...
- Spring Cache抽象详解
缓存简介 缓存,我的理解是:让数据更接近于使用者:工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存):缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/I ...
- 25. Spring Boot与缓存 JSR-107、Spring缓存抽象
JSR107 Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry和Expiry. CachingProvider ...
- Spring Environment(三)生命周期
Spring Environment(三)生命周期 Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html) Spring Envi ...
- 转:Spring Cache抽象详解
缓存简介 缓存,我的理解是:让数据更接近于使用者:工作机制是:先从缓存中读取数据,如果没有再从慢速设备上读取实际数据(数据也会存入缓存):缓存什么:那些经常读取且不经常修改的数据/那些昂贵(CPU/I ...
- Spring 缓存抽象
Spring从3.1开始定义了org.springframework.cache.Cache和org.springframework.cache.CacheManager接口来统一不同的缓存技术:并支 ...
- spring Environment
Environment 环境在容器中是一个抽象的集合,是指应用环境的2个方面: profiles和 properties. profile 配置是一个被命名的,bean定义的逻辑组,这些bean只有在 ...
随机推荐
- 简明Python3教程 4.安装
如果你已经安装了Python 2.x,你不需要在安装Python 3.0前卸载Python 2.x.这两者可以共存. GNU/Linux用户和BSD用户 如果你使用类似于Ubuntu.Fedora.O ...
- c#开发移动APP-Xamarin入门扩展
原文:c#开发移动APP-Xamarin入门扩展 这节主要演示了如何通过添加第二个屏幕来跟踪应用程序的call历史来扩展Phoneword应用程序.最终如下: 按如下步骤扩展Phoneword 在Ph ...
- WPF“天狗食月”效果
原文:WPF"天狗食月"效果 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/yangyisen0713/article/deta ...
- corefx 源码学习:NetworkStream.ReadAsync 是如何从 Socket 异步读取数据的
最近遇到 NetworkStream.ReadAsync 在 Linux 上高并发读取数据的问题,由此激发了阅读 corefx 中 System.Net.Sockets 实现源码(基于 corefx ...
- 服务器做RAID10
将接上Raid card的机器开机,根据提示按组合键进入Raid配置界面(一般是按Ctrl+H,具体的根据提示进行即可) 点击Configuration Wizard,选择new configur ...
- JS表格各行变色
<head> <title></title> <script type="text/javascript"> ...
- List集合去重方式及效率对比
List集合相信大家在开发过程中几乎都会用到.有时候难免会遇到集合里的数据是重复的,需要进行去除.然而,去重方式有好几种方式,你用的是哪种方式呢?去重方式效率是否是最高效.最优的呢?今天就给大家讲解一 ...
- Android Xposed框架出现java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation问题
第一次玩Xposed框架,按照多个demo的格式写了一个demo发现死活不进入 public abstract void handleLoadPackage(LoadPackageParam lppa ...
- Win8Metro(C#)数字图像处理--2.29图像除法运算
原文:Win8Metro(C#)数字图像处理--2.29图像除法运算 [函数名称] 图像除法函数DivisionProcess(WriteableBitmap src, WriteableBit ...
- 小记同学一次奇葩的DNS欺骗实验失败经历
这是一个DNS欺骗实验,使用kali的ettercap.有受害者.攻击者(虚拟机).Web服务器三台机器.受害者的事124.16.70.105虚拟机的是124.16.71.48web服务器是124.1 ...