Spring Environment(二)源码分析
Spring Environment(二)源码分析
Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)
Spring Environment 属性配置管理系列文章:
一、Environment 接口

public interface Environment extends PropertyResolver {
String[] getActiveProfiles();
String[] getDefaultProfiles();
// @since 5.1 废弃,改用 Profiles(Profiles.of("dev"))
@Deprecated
boolean acceptsProfiles(String... profiles);
boolean acceptsProfiles(Profiles profiles);
}
Environment 是对 JDK 环境、Servlet 环境的抽象,可以获取剖面相关的信息。同时实现了 PropertyResolver 接口用于解析属性占位符和类型转换,实际上是委托给 PropertySourcesPropertyResolver 完成的。
在其子类 ConfigurableEnvironment 接口中还提供了设置剖面和相关数据的 API。
public interface ConfigurableEnvironment extends Environment, ConfigurablePropertyResolver {
// 1. 设置剖面
void setActiveProfiles(String... profiles);
void addActiveProfile(String profile);
void setDefaultProfiles(String... profiles);
// 2. 属性源
MutablePropertySources getPropertySources();
Map<String, Object> getSystemProperties();
Map<String, Object> getSystemEnvironment();
// 3. 合并两个环境信息
void merge(ConfigurableEnvironment parent);
}
二、Environment 默认实现类
Environment 的主要几个实现如下所示:
MockEnvironment:模拟的环境,用于测试时使用;StandardEnvironment:标准环境,普通 Java 应用时使用,会自动注册 System.getProperties() 和 System.getenv()到环境;StandardServletEnvironment:标准 Servlet 环境,其继承了 StandardEnvironment,Web 应用时使用,除了 StandardEnvironment 外,会自动注册 ServletConfig(DispatcherServlet)、ServletContext 及 JNDI 实例到环境;
StandardEnvironment 标准的 JDK 环境实现如下,将 OS 和 JVM 相关的配置信息都交由 StandardEnvironment 管理。
2.1 StandardEnvironment
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";
@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()));
}
}
2.2 StandardServletEnvironment
StandardServletEnvironment 除了注册系统变量外,还会自动注册 ServletConfig(DispatcherServlet)、ServletContext 及 JNDI 实例到环境;
public class StandardServletEnvironment extends StandardEnvironment implements ConfigurableWebEnvironment {
/** Servlet context init parameters property source name: {@value}. */
public static final String SERVLET_CONTEXT_PROPERTY_SOURCE_NAME = "servletContextInitParams";
/** Servlet config init parameters property source name: {@value}. */
public static final String SERVLET_CONFIG_PROPERTY_SOURCE_NAME = "servletConfigInitParams";
/** JNDI property source name: {@value}. */
public static final String JNDI_PROPERTY_SOURCE_NAME = "jndiProperties";
protected void customizePropertySources(MutablePropertySources propertySources) {
propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));
propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));
if (JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {
propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));
}
super.customizePropertySources(propertySources);
}
// 调用 initPropertySources 替换对应的占位符
@Override
public void initPropertySources(@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
WebApplicationContextUtils.initServletPropertySources(getPropertySources(), servletContext, servletConfig);
}
其中 customizePropertySources 方法是在其父类 AbstractEnvironment 的构造方法中调用的,此时 ServletConfig 和 ServletContext 相关的信息还未初始化,因此需要一个占位符,在初始化 WEB 时自动替换。
public static void initServletPropertySources(MutablePropertySources sources,
@Nullable ServletContext servletContext, @Nullable ServletConfig servletConfig) {
Assert.notNull(sources, "'propertySources' must not be null");
String name = StandardServletEnvironment.SERVLET_CONTEXT_PROPERTY_SOURCE_NAME;
if (servletContext != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
sources.replace(name, new ServletContextPropertySource(name, servletContext));
}
name = StandardServletEnvironment.SERVLET_CONFIG_PROPERTY_SOURCE_NAME;
if (servletConfig != null && sources.contains(name) && sources.get(name) instanceof StubPropertySource) {
sources.replace(name, new ServletConfigPropertySource(name, servletConfig));
}
}
三、AbstractEnvironment
Environment 的源码非常简单,就不多说了。
3.1 属性定义
(1) 常量
// 为 true 时 getSystemEnvironment() 返回空集合,屏蔽 OS 相关信息
public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
// 剖面相关的配置
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";
(2) 属性
// 剖面信息,查找时先从 activeProfiles 再从 defaultProfiles 中查找
private final Set<String> activeProfiles = new LinkedHashSet<>();
private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());
// 属性源
private final MutablePropertySources propertySources = new MutablePropertySources();
// propertyResolver 用于解析属性占位符和类型转换
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
3.2 剖面相关的 API
public boolean acceptsProfiles(String... profiles) {
Assert.notEmpty(profiles, "Must specify at least one profile");
for (String profile : profiles) {
if (StringUtils.hasLength(profile) && profile.charAt(0) == '!') {
if (!isProfileActive(profile.substring(1))) {
return true;
}
} else if (isProfileActive(profile)) {
return true;
}
}
return false;
}
protected boolean isProfileActive(String profile) {
// 只要 profile 不为空且不以 ! 开头
validateProfile(profile);
Set<String> currentActiveProfiles = doGetActiveProfiles();
return (currentActiveProfiles.contains(profile) ||
(currentActiveProfiles.isEmpty() && doGetDefaultProfiles().contains(profile)));
}
获取剖面信息如下:
@Override
public String[] getActiveProfiles() {
return StringUtils.toStringArray(doGetActiveProfiles());
}
// 获取 activeProfiles,defaultProfiles 类似
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;
}
}
3.3 获取属性
private final ConfigurablePropertyResolver propertyResolver =
new PropertySourcesPropertyResolver(this.propertySources);
@Override
public String getProperty(String key) {
return this.propertyResolver.getProperty(key);
}
获取属性都委托给 propertyResolver 完成了,propertyResolver 持有 propertySources 数据源,可以解析占位符和进行类型转换。
PropertyResolver 的使用参考:https://www.cnblogs.com/binarylei/p/10284826.html
每天用心记录一点点。内容也许不重要,但习惯很重要!
Spring Environment(二)源码分析的更多相关文章
- 十、Spring之BeanFactory源码分析(二)
Spring之BeanFactory源码分析(二) 前言 在前面我们简单的分析了BeanFactory的结构,ListableBeanFactory,HierarchicalBeanFactory,A ...
- Spring Developer Tools 源码分析:二、类路径监控
在 Spring Developer Tools 源码分析一中介绍了 devtools 提供的文件监控实现,在第二部分中,我们将会使用第一部分提供的目录监控功能,实现对开发环境中 classpath ...
- Spring IOC 容器源码分析系列文章导读
1. 简介 Spring 是一个轻量级的企业级应用开发框架,于 2004 年由 Rod Johnson 发布了 1.0 版本.经过十几年的迭代,现在的 Spring 框架已经非常成熟了.Spring ...
- Spring Developer Tools 源码分析:三、重启自动配置'
接上文 Spring Developer Tools 源码分析:二.类路径监控,接下来看看前面提到的这些类是如何配置,如何启动的. spring-boot-devtools 使用了 Spring Bo ...
- Spring IOC 容器源码分析 - 余下的初始化工作
1. 简介 本篇文章是"Spring IOC 容器源码分析"系列文章的最后一篇文章,本篇文章所分析的对象是 initializeBean 方法,该方法用于对已完成属性填充的 bea ...
- Spring IOC 容器源码分析 - 填充属性到 bean 原始对象
1. 简介 本篇文章,我们来一起了解一下 Spring 是如何将配置文件中的属性值填充到 bean 对象中的.我在前面几篇文章中介绍过 Spring 创建 bean 的流程,即 Spring 先通过反 ...
- Spring IOC 容器源码分析 - 循环依赖的解决办法
1. 简介 本文,我们来看一下 Spring 是如何解决循环依赖问题的.在本篇文章中,我会首先向大家介绍一下什么是循环依赖.然后,进入源码分析阶段.为了更好的说明 Spring 解决循环依赖的办法,我 ...
- Spring IOC 容器源码分析 - 创建原始 bean 对象
1. 简介 本篇文章是上一篇文章(创建单例 bean 的过程)的延续.在上一篇文章中,我们从战略层面上领略了doCreateBean方法的全过程.本篇文章,我们就从战术的层面上,详细分析doCreat ...
- Spring IOC 容器源码分析 - 创建单例 bean 的过程
1. 简介 在上一篇文章中,我比较详细的分析了获取 bean 的方法,也就是getBean(String)的实现逻辑.对于已实例化好的单例 bean,getBean(String) 方法并不会再一次去 ...
- Spring IOC 容器源码分析 - 获取单例 bean
1. 简介 为了写 Spring IOC 容器源码分析系列的文章,我特地写了一篇 Spring IOC 容器的导读文章.在导读一文中,我介绍了 Spring 的一些特性以及阅读 Spring 源码的一 ...
随机推荐
- 2018面向对象程序设计(Java) 第2周学习指导及要求
2018面向对象程序设计(Java) 第2周学习指导及要求(2018.9.3-2018.9.9) 学习目标 适应老师教学方式,能按照自主学习要求完成本周理论知识学习: 掌握Java Applica ...
- centos最小安装之后无法使用ifconfig
Centos7安装之后,无法使用ifconfig(找不到命令) 运行 yum install provides 再安装net-tools即可 yum install net-tools 没有网,下载r ...
- CentOS Netstat命令
语法 netstat(选项) 选项 -a或--all:显示所有连线中的Socket: -A<网络类型>或--<网络类型>:列出该网络类型连线中的相关地址: -c或--conti ...
- Vue之常用语法
变量的定义: var定义的变量:只有全局作用域和函数作用域.有变量提升,先打印后定义变量不会报错,打印结果为undefined let定义的变量:没有变量提升 ——>有局 ...
- DBCP连接数据库了解一下
---恢复内容开始--- package com.kevin.Utils; import javax.sql.DataSource; import org.apache.commons.dbcp.Ba ...
- laravel excel导出调节列宽度,对某列中数据颜色处理
//$cellData 表格标题栏各名称数组 //$result 表格内容数组//$items getForDataTable得到的表格数据 $result = array_merge($cellDa ...
- c# 键值对的方式post提交
DataContractJsonSerializer jsQcData = new DataContractJsonSerializer(typeof(DATA<data>));//DAT ...
- Cisco 4507R+E四引擎VSS故障解决
如果可以要做双引擎VSS(每个机箱1个引擎), 3.6.7版本可以实现 如果需要做4引擎VSS(每个机箱2个引擎) 请使用3.8.x和之后的版本.
- C# 页面向controller中跳转匹配方法的时候,当controller中有两个重载方法时候,不发生跳转
在ajax中的URL跳向controller一个方法时候,controller中有两个重载的方法,ajax不发生跳转,当删除另外一个方法之后,正常跳转. 不知道,是我自己写的有问题,还是control ...
- JavaScript各种继承方式(四):原型式继承(prototypal inheritance)
一 原理 利用工具函数,通过原型对象直接得到父类的实例,并当作子类对实例使用. function inherit(obj){ // 在闭包中创建子类,对外隐藏子类 function Temp(){ } ...