目录
一、理解Environment的设计
(一)整体理解
(二)聚焦Profiles分析
(三)聚焦Properties分析
二、Environment类图结构分析
三、PropertyResolver源码分析
(一)源码展示说明
(二)源码理解分析
四、Environment源码分析
五、ConfigurableEnvironment源码分析
(一)源码展示
(二)如何理解
六、AbstractEnvironment简单说明
七、其与IOC容器的关系分析
(一)单独来看
(二)关系型分析来看
一、理解Environment的设计
(一)整体理解
之前我们在分析分析SpringBoot启动配置原理_springboot启动机制-CSDN博客的时候对应Environment已经有一定的了解了,本次对其聚焦进行更加深层次的理解和分析:
Environment模块在 Spring 中主要负责管理应用程序的配置和环境(定义为一组 profile配置文件)相关的信息,每个 profile 对应一个特定的应用程序部署环境,比如开发、测试、生产等。
在这些 profile 中,可以包含各种属性,比如数据库连接信息、服务器端口、日志级别等。而
对应的属性在 Spring 中被表示为键值对,其中键是属性的名称,值是属性的取值。属性可以通过不同的方式进行配置,比如在属性文件中、通过系统属性、操作系统环境变量等。
(二)聚焦Profiles分析
专注于 Environment 模块中Profiles 的核心概念,从设计上来看其基本功能的话,个人觉得主要是以下三方面:
-
环境分离与配置隔离: Profiles 允许将不同的配置信息与不同的部署环境(如开发、测试、生产)进行关联。通过定义不同的 profile,可以在不同的环境中使用不同的配置信息,从而实现了环境之间的隔离和配置的分离。这样做有助于提高应用程序的灵活性和可维护性。
-
适应多种环境: Spring Environment 允许为每个 profile 定义不同的配置信息,这使得应用程序可以适应多种不同的部署环境。比如在开发环境中可以使用内存数据库,而在生产环境中则使用真实的数据库。
-
条件化配置: Profiles 支持条件化配置,可以根据运行时的条件选择加载特定的 profile。这可以通过
@Profile
注解或在配置文件中使用spring.profiles.active
属性来实现。这样可以根据运行时的条件动态地决定使用哪个 profile,进而决定加载哪些配置信息。
这里如果看源码的话,Profiles 是支持继承的,即可以定义一个通用的 profile,并在其他 profile 中引用或继承这个通用的 profile来避免重复定义相似的配置信息。同时Profiles 可以与外部化配置(如属性文件、YAML 文件)结合使用,通过不同的 profile 加载不同的外部化配置文件。
(三)聚焦Properties分析
Properties负责管理应用程序的配置信息主要功能如下:
-
抽象化和统一访问: Properties 提供了一个抽象化的方式来管理配置信息,通过统一的接口访问配置信息,使得应用程序不需要关心配置信息的具体来源,可以将其抽象为一组键值对。
-
支持多种配置源: Properties 支持从多种不同的配置源中获取配置信息。这些配置源可以包括属性文件(如
.properties
文件、.yaml
文件)、系统属性、操作系统环境变量等。 -
属性解析和占位符替换: Properties 支持属性解析和占位符替换,可以在配置文件中使用
${...}
占位符来引用其他配置属性,以及在运行时动态替换这些占位符为实际的属性值。 -
属性优先级: Properties 支持属性优先级设置,可以指定不同来源的属性之间的优先级。例如,系统属性可以优先于配置文件属性,配置文件属性可以优先于默认值。
-
监听器支持: Properties 支持监听器(
EnvironmentPostProcessor
),可以在 Spring 应用程序启动时对 Properties 进行修改和定制化。
二、Environment类图结构分析
Environment
接口本身是一个顶层接口,Environment
接口的实现类通常是通过组合其他类来实现其功能的,基本关系图梳理如下:(其实这部分读源码理解对平时的开发有很大的指导性,建议直接阅读下并应用到平时的开发中)
整体来看的话,PropertyResolver
、ConfigurablePropertyResolver
提供了属性解析和配置属性的功能,Environment
和 ConfigurableEnvironment
则扩展了属性解析器和配置管理器的功能,从而实现了更全面的环境配置。
AbstractEnvironment
、StandardEnvironment
是 Environment
接口的具体实现类,提供了默认的环境配置功能。ConfigurableWebEnvironment
、StandardReactiveWebEnvironment
和 StandardServletEnvironment
则是针对特定类型的 Web 应用程序环境配置的具体实现类。
类/接口 | 描述 |
---|---|
PropertyResolver | 定义了解析属性的方法,提供获取属性值、解析占位符等功能。 |
ConfigurablePropertyResolver | PropertyResolver 扩展,提供配置属性的功能,如设置属性、忽略属性等。 |
Environment | 整个Spring应用环境,提供获取配置属性、管理 Profiles、处理属性源等功能。 |
ConfigurableEnvironment | Environment 扩展,定义了配置环境的一些额外功能,如设置激活的 Profiles、添加属性源等。 |
AbstractEnvironment | Environment 的抽象实现类,同时也实现了 ConfigurableEnvironment 接口,提供了通用的环境配置功能和默认实现。 |
StandardEnvironment | AbstractEnvironment 的具体实现类,提供了对系统属性、环境变量、JNDI、PropertySource 等的支持,是 Spring 中最常用的环境实现之一。 |
ConfigurableWebEnvironment | ConfigurableEnvironment 扩展,特定于 Web 应用程序的环境配置,提供了一些额外的 Web 相关的配置功能,如 Servlet 上下文、Servlet 配置等。 |
StandardReactiveWebEnvironment | ConfigurableWebEnvironment 的具体实现类,适用于响应式 Web 应用程序的环境配置,提供了对响应式 Web 环境的支持。 |
StandardServletEnvironment | ConfigurableWebEnvironment 的另一个具体实现类,适用于传统的 Servlet Web 应用程序的环境配置,提供了对 Servlet 上下文和 Servlet 配置的支持。 |
我们下面会通过几个重点的接口类进行分析。
三、PropertyResolver源码分析
(一)源码展示说明
PropertyResolver
接口是用于解析属性的基础接口,定义了获取属性值、解析占位符等方法。
public interface PropertyResolver {/*** 根据给定的属性键获取属性值。* @param key 属性键* @return 对应的属性值,如果属性不存在则返回 null*/String getProperty(String key);/*** 根据给定的属性键获取属性值,如果属性不存在则返回默认值。* @param key 属性键* @param defaultValue 默认值* @return 对应的属性值,如果属性不存在则返回默认值*/String getProperty(String key, String defaultValue);/*** 检查是否存在给定属性键的属性。* @param key 属性键* @return 如果存在则返回 true,否则返回 false*/boolean containsProperty(String key);/*** 解析给定文本中的占位符,并替换为实际的属性值。* @param text 要解析的文本* @return 解析后的文本*/String resolvePlaceholders(String text);
}
(二)源码理解分析
PropertyResolver
接口就像是一个通用的属性查询器,它专门负责查找应用程序中的配置信息,比如数据库连接、服务端口等。它的设计思想是让应用程序的各个组件不必自己去查找这些配置信息,而是交给一个专门的工具来处理。这样做有两个好处,一是提高了代码的模块化和可维护性,二是让配置信息更容易被统一管理和修改,让程序更加灵活和易用。
四、Environment源码分析
Environment
表示整个应用程序环境的接口,定义了一些方法来获取配置属性、处理 Profiles、管理属性源等。部分源码展示如下:
import org.springframework.core.env.PropertyResolver;
import org.springframework.core.env.Profiles;public interface Environment extends PropertyResolver {/*** 获取活动的 Profiles。* @return 活动的 Profiles*/String[] getActiveProfiles();/*** 获取默认的 Profiles。* @return 默认的 Profiles*/String[] getDefaultProfiles();/*** 检查是否接受给定的 Profiles。* @param profiles 要检查的 Profiles* @return 如果接受则返回 true,否则返回 false*/boolean acceptsProfiles(Profiles profiles);// 其他方法...
}
Environment
接口继承自 PropertyResolver
接口,因此它具有属性解析的能力,可以通过 getProperty
方法来获取配置属性的值,通过 resolvePlaceholders
方法来解析属性值中的占位符。除此之外,Environment
还定义了一些关于 Profiles 管理的方法,用于管理应用程序的配置文件、属性源等。在实际应用中,Spring Framework 提供了多个具体实现类,如 StandardEnvironment
、StandardServletEnvironment
等,用于实现 Environment
接口的功能,并为应用程序提供环境配置的支持。
五、ConfigurableEnvironment源码分析
(一)源码展示
继承自 Environment
接口,并定义了一些额外的配置管理功能。展示了部分方法和属性:
import org.springframework.core.env.MutablePropertySources;
import org.springframework.core.env.PropertySource;public interface ConfigurableEnvironment extends Environment {/*** 设置活动的 Profiles。* @param profiles 活动的 Profiles*/void setActiveProfiles(String... profiles);/*** 添加一个属性源。* @param propertySource 要添加的属性源*/void addPropertySource(PropertySource<?> propertySource);/*** 获取所有的属性源。* @return 所有的属性源*/MutablePropertySources getPropertySources();// 其他方法...
}
(二)如何理解
ConfigurableEnvironment
接口的设计就像是给应用程序一个"可塑造的环境",让你可以根据需要来定制和管理你的应用程序的环境。
想象一下,应用程序就像是一个小花园,而 ConfigurableEnvironment
就是提供了一些工具,让你可以在这个花园中种植不同的花草、设计不同的景观。
setActiveProfiles
方法就像是给你一桶颜料,让你可以选择不同的颜色来装饰你的花园。你可以选择激活不同的 "profile",比如 "开发"、"测试"、"生产" 等,以适应不同的环境和需求。addPropertySource
方法就像是给你提供了一些花盆,让你可以往花园里添加不同种类的植物。你可以通过添加属性源来灵活地管理你的配置信息,比如从文件中读取配置、从数据库中读取配置等。getPropertySources
方法就像是给你提供了一个花园地图,让你可以清楚地了解你花园中都有哪些植物。你可以通过获取属性源来查看和管理你的配置信息。
ConfigurableEnvironment
就是为了让应用程序更加灵活和可塑造而设计的可以适应不同的场景和需求。
六、AbstractEnvironment简单说明
AbstractEnvironment
使用模板方法模式定义了一个基本骨架,getPropertySources()
方法就是一个典型的模板方法,而具体的属性源管理实现则留给了子类去完成。
具体来说,在 AbstractEnvironment
的构造函数中,会初始化 propertySources
对象,然后通过 getPropertySources()
方法,子类可以获取这个 propertySources
对象,并对其进行操作,完成具体的属性源管理逻辑。
有几个主要的子类都有特定的用途和环境条件:
-
StandardEnvironment:
AbstractEnvironment
的标准实现,用于标准的应用程序环境。适用于大多数的应用场景,提供了对系统属性、环境变量等的支持,可以用于加载和管理应用程序的配置信息。 -
StandardServletEnvironment:扩展了
StandardEnvironment
,并添加了对 Servlet 上下文参数、Servlet 初始化参数等的支持。适用于基于 Servlet 容器(如 Tomcat、Jetty 等)的应用程序环境。 -
StandardReactiveWebEnvironment:是针对响应式 Web 环境的实现,适用于使用 Spring WebFlux 框架的应用程序。扩展了
StandardEnvironment
,并添加了对响应式 Web 环境的特定支持。 -
MockEnvironment:用于测试目的的环境模拟类,提供模拟的环境实现,用于在单元测试和集成测试中模拟不同的环境条件,如不同的配置信息、Profiles 等。
七、其与IOC容器的关系分析
(一)单独来看
-
IOC 容器的作用:负责管理应用程序中的对象(Bean),并处理它们之间的依赖关系。IOC 容器通过将对象的创建、组装和管理工作交给容器来实现对象之间的解耦和松耦合。
-
Environment 的作用:用于表示应用程序环境的接口,负责管理和处理应用程序的配置信息,比如配置文件、系统属性等,提供一种统一的方式来获取和解析配置属性,使得应用程序可以根据不同的环境条件来加载不同的配置信息。
(二)关系型分析来看
IOC 容器需要获取应用程序的配置信息来创建和初始化对象,而 Environment
就是负责管理和提供这些配置信息的。在 Spring 应用程序启动时,IOC 容器会通过 Environment
接口来获取配置信息,并根据配置信息来完成 Bean 的装配和初始化工作。
通常情况下,IOC 容器会将 Environment
对象作为一个重要的组件来进行配置和初始化,以确保应用程序能够正确地获取和使用配置信息。在 Spring Framework 中,ApplicationContext
接口是 IOC 容器的主要实现类之一,通常会与 Environment
接口紧密配合,以实现对配置信息的管理和使用。具体可见:分析SpringBoot启动配置原理_springboot启动机制-CSDN博客文章浏览阅读1.5w次,点赞10次,收藏28次。分析SpringBoot启动配置原理:给出整体初步分析和对应流程图,并从三方面进行展开分析(SpringApplication构造过程分析+SpringApplication启动过程分析+SpringBoot自动配置分析)_springboot启动机制https://blog.csdn.net/xiaofeng10330111/article/details/130903779?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171389467716800182742131%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=171389467716800182742131&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_ecpm_v1~rank_v31_ecpm-2-130903779-null-null.nonecase&utm_term=%E5%90%AF%E5%8A%A8&spm=1018.2226.3001.4450源码或官方文章
Java-based Container Configuration :: Spring Framework
Bean Scopes :: Spring Framework
Container Overview :: Spring Framework