Spring运行环境Environment的解析

 更新时间:2023年08月01日 09:15:18   作者:韩长奇  
本文主要介绍了Spring运行环境Environment的解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

Spring运行环境

Spring在创建容器时,会创建Environment环境对象,用于保存spring应用程序的运行环境相关的信息。在创建环境时,需要创建属性源属性解析器,会解析属性值中的占位符,并进行替换。

创建环境时,会通过System.getProperties()获取JVM系统属性,会通过System.getenv()获取JVM环境属性。

Environment在Spring中的使用

spring在创建容器时需要指定需要加载配置文件路径,在加载配置文件路径时,需要解析字符串中的占位符。解析占位符时,需要环境信息,此时会创建一个标准的spring运行环境,即创建StandardEnvironment对象。

1、调用setConfigLocations方法给spring设置需要加载的配置文件的路径,源码如下:

// 将配置文件的路径放到configLocations 字符串数组中
public void setConfigLocations(@Nullable String... locations) {
    if (locations != null) {
        Assert.noNullElements(locations, "Config locations must not be null");
        // 设置了几个配置文件,就创一个多长的字符串数组,用来存放配置文件的路径
        this.configLocations = new String[locations.length];
        for (int i = 0; i < locations.length; i++) {
            //解析路径,将解析的路径存放到字符串数组中
            this.configLocations[i] = resolvePath(locations[i]).trim();
        }
    }
    else {
        this.configLocations = null;
    }
}

2、调用resolvePath方法解析配置文件路径中的占位符,源码如下:

// 解析给定的路径,必要时用相应的环境属性值替换占位符。应用于配置位置。
protected String resolvePath(String path) {
    // 获取环境,解决所需的占位符
    return getEnvironment().resolveRequiredPlaceholders(path);
}

3、调用getEnvironment方法获取环境信息,如果没有指定spring的环境信息,通过createEnvironment获取默认的环境,也就是spring的标准环境。getEnvironment方法源码如下:

// 获取spring的环境信息,如果没有指定,获取到的时默认的环境
@Override
public ConfigurableEnvironment getEnvironment() {
    if (this.environment == null) {
        this.environment = createEnvironment();
    }
    return this.environment;
}

4、调用createEnvironment方法获取默认的环境(spring的标准环境),使用StandardEnvironment无参构造创建对象。源码如下:

// 获取默认的环境
protected ConfigurableEnvironment createEnvironment() {
    return new StandardEnvironment();
}

Spring的标准环境StandardEnvironment

Spring的标准环境StandardEnvironment适合在非web应用程序中使用。

在AbstractApplicationContext类的createEnvironment方法中会调用StandardEnvironment的无参构造方法创建环境对象。

1、调用StandardEnvironment的无参构造方法,该方法中没有任何逻辑处理,源码如下:

public StandardEnvironment() {}

2、StandardEnvironment类是AbstractEnvironment抽象类的子类,因此使用StandardEnvironment的无参构造创建对象时会调用父类AbstractEnvironment的无参构造方法。AbstractEnvironment在下文中有描述。

3、重写AbstractEnvironment类中的customizePropertySources方法,用于设置属性源,该方法通过父类进行回调。
该方法会获取JVM系统属性和环境属性并设置到MutablePropertySources类中存放属性源的CopyOnWriteArrayList中。

1)JVM系统属性通过System.getProperties()获取;
2)环境属性通过System.getenv()获取。

StandardEnvironment类中customizePropertySources方法源码如下:

// 设置属性源,JVM系统属性中的属性将优先于环境属性中的属性。
@Override
protected void customizePropertySources(MutablePropertySources propertySources) {
    /**
     * 1、MutablePropertySources类中使用CopyOnWriteArrayList存储属性源,集合中存储PropertySource的子类
     * 2、PropertiesPropertySource是PropertySource的子类,PropertySource类中有三个成员变量
     *         1)logger:日志对象
     *         2)name:用来保存属性源名称
     *         3)source:用来保存属性源中的属性
     */
    // getSystemProperties():通过System.getProperties()获取JVM属性键值对,并转成Map
    propertySources.addLast(
            new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
    // getSystemEnvironment():通过System.getenv()获取环境属性键值对,并撰成Map
    propertySources.addLast(
            new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

4、StandardEnvironment类中设置了两个静态常量:

1)systemEnvironment:以系统环境为属性源
2)systemProperties:以JVM系统属性为属性源

/** System environment property source name: {@value}.
 * 系统环境属性源名:{@value}。 */
public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
/** JVM system properties property source name: {@value}.
 * JVM系统属性属性源名称:{@value}。*/
public static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";

Spring的抽象环境AbstractEnvironment

StandardEnvironment类是AbstractEnvironment抽象类的子类,因此使用StandardEnvironment的无参构造创建对象时会调用父类AbstractEnvironment的无参构造方法。

1、AbstractEnvironment的无参构造方法,该方法会调用AbstractEnvironment的有参构造方法,源码如下:

public AbstractEnvironment() {
    this(new MutablePropertySources());
}

2、AbstractEnvironment的有参构造
该方法的主要做三件事:
1)给成员变量赋值
2)创建属性源属性解析器
3)调用子类重写的customizePropertySources方法(方法回调)。虽然方法回调在成员变量的赋值之后,但由于是引用传递,所以通过成员属性可以获取到改变之后的值。

// 使用了模板方法设计模式。
// 给成员变量赋值,并调用子类重写的方法,对propertySources进行操作。
protected AbstractEnvironment(MutablePropertySources propertySources) {
    // 给全局变量 可变属性源 赋值
    this.propertySources = propertySources;
    // 创建属性解析器:PropertySourcesPropertyResolver 属性源属性解析器
    this.propertyResolver = createPropertyResolver(propertySources);
    // 自定义属性源,此处回调子类重写的方法。子类通过重写该方法可以操作propertySources。spring标准环境StandardEnvironment重写了该方法
    customizePropertySources(propertySources);
}

3、调用createPropertyResolver创建属性解析器,用于解析属性值中的占位符并进行替换。

// 在创建环境时,需要创建属性解析器
protected ConfigurablePropertyResolver createPropertyResolver(MutablePropertySources propertySources) {
    return new PropertySourcesPropertyResolver(propertySources);
}

4、AbstractEnvironment的成员属性

// 指示Spring忽略系统环境变量,默认值为"false"。
// false表示不会忽略系统环境变量,此时getSystemEnvironment方法会调用System.getenv()获取环境属性
// true表示会忽略系统的环境变量,此时getSystemEnvironment方法会返回一个空的Map
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";
// 日志对象
protected final Log logger = LogFactory.getLog(getClass());
//系统启动时使用的配置文件
private final Set<String> activeProfiles = new LinkedHashSet<>();
// 默认配置文件
private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());
// 可变属性源,使用该成员变量保存属性源及通过该属性源获取的属性
private final MutablePropertySources propertySources;
// 可配置的属性解析器
private final ConfigurablePropertyResolver propertyResolver;

到此这篇关于Spring运行环境Environment的解析的文章就介绍到这了,更多相关Spring Environment内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • JAVA音频处理依赖库示例操作大全(从格式转换到音频拼接)

    JAVA音频处理依赖库示例操作大全(从格式转换到音频拼接)

    在现代应用开发中,音频处理是常见需求,包括格式转换、音频拼接、剪辑、降噪等操作,本教程将介绍Spring Boot中常用的音频处理依赖库,比较它们的特性、区别及社区活跃程度,并提供实用代码示例,感兴趣的朋友跟随小编一起看看吧
    2025-10-10
  • Java实现邮件发送功能

    Java实现邮件发送功能

    这篇文章主要为大家详细介绍了Java实现邮件发送功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • spring入门教程之bean的继承与自动装配详解

    spring入门教程之bean的继承与自动装配详解

    众所周知Spring里面的bean就类似是定义的一个组件,而这个组件的作用就是实现某个功能的,下面这篇文章主要给大家介绍了关于spring入门教程之bean继承与自动装配的相关资料,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2017-11-11
  • java中对list分页并显示数据到页面实例代码

    java中对list分页并显示数据到页面实例代码

    这篇文章主要介绍了java中对list分页并显示数据到页面实例代码,分享了相关代码示例,小编觉得还是挺不错的,具有一定借鉴价值,需要的朋友可以参考下
    2018-02-02
  • Spring调用this导致事务失效的三种解决方案

    Spring调用this导致事务失效的三种解决方案

    在 Spring 事务管理 中,如果你在同一个类的方法内部使用 this.xxx() 调用另一个带 @Transactional 的方法,事务很可能会失效,这不是玄学,而是代理机制在背后打盹了,本文就给大家介绍如何解决this调用导致事务失效问题,需要的朋友可以参考下
    2026-02-02
  • Java+opencv3.2.0实现人脸检测功能

    Java+opencv3.2.0实现人脸检测功能

    这篇文章主要为大家详细介绍了Java+opencv3.2.0实现人脸检测功能,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-02-02
  • 从零带你手写Java七种负载均衡算法实现方案

    从零带你手写Java七种负载均衡算法实现方案

    在分布式系统,微服务架构以及高并发场景中,负载均衡是一项至关重要的技术本文将带你纯手写实现七种常见的负载均衡算法,全部使用 Java 编写,不依赖任何第三方框架,帮助你深入理解其核心原理与适用场景
    2026-02-02
  • Java的Character类详解

    Java的Character类详解

    在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情况。为了解决这个问题,Java语言为内置数据类型char提供了包装类Character类。本文详细介绍了Java的Character类,感兴趣的同学可以参考阅读
    2023-04-04
  • 盘点Java中延时任务的多种实现方式

    盘点Java中延时任务的多种实现方式

    当需要一个定时发布系统通告的功能,如何实现? 当支付超时,订单自动取消,如何实现?其实这些问题本质都是延时任务的实现,本文为大家盘点了多种常见的延时任务实现方法,希望对大家有所帮助
    2022-12-12
  • SpringBoot 自动配置失效的解决方法

    SpringBoot 自动配置失效的解决方法

    本文主要介绍了SpringBoot 自动配置失效的解决方法,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-11-11

最新评论