一次性理清Environment体系

embedded/2024/10/18 17:45:55/

在Spring中,我们可以通过配置文件等方式去进行一些属性值的配置,比如通过@Value注解去获取到对应的属性值,又或者说是想在程序运行时获取系统环境变量,类似的这些操作其实都是去获取一些配置数据,所以在Spring中对这些数据的提供了一个Environment组件,该组件放着的就是这些属性值,并且提供了相应的API给用户去获取,接下来我们就去看一下整个 Environment的结构体系是怎样的

类继承体系

整个Environment的类接口体系如上:

  • PropertyResolver:属性解析器,为什么Environment作为配置环境的顶级接口需要去继承自这个属性解析器接口呢?那是因为当我们从Environment中去获取某个属性值的时候,传入的key是带有占位符的,比如@Value("${user.name}"),拿到的key就是${user.name},此时Environment就需要把${}这个占位符去掉,而这个任务Environment则是交给PropertyResolver去做的,所以这里其实就是Environment对PropertyResolver做了一层包装代理,也就可以顺理成章地继承PropertyResolver接口并交给子类实现其方法
  • ConfigurablePropertyResolver:在属性解析器PropertyResolver的基础上增加了一些开放给用户的配置属性的方法,比如配置解析的占位符前缀后缀,配置是否抛出解析错误的异常等等
  • Environment:Spring环境组件的顶级接口
  • ConfigurableEnvironment:在顶级接口Environment的基础上开放了相关属性可配置的方法,比如设置profile,设置PropertySource等等
  • AbstractEnvironment:继承于ConfigurableEnvironment接口,对一些公共方法进行了统一实现
  • StandardEnvironment:标准的Spring环境实现,在该实现中可以获取到系统环境的属性以及JVM的属性

PropertyResolver

属性解析器,如果我们使用了占位符去获取对应的属性值,那么第一件事就是需要对占位符进行解析才能根据里面的key去找到对应的属性值,而属性解析器就是专门干这个活的

java">public interface PropertyResolver {/*** 是否包含指定key的属性*/boolean containsProperty(String key);/*** 根据指定的key获取对应的属性值* @param key 要解析的属性名* @see #getProperty(String, String)* @see #getProperty(String, Class)* @see #getRequiredProperty(String)*/@NullableString getProperty(String key);/*** 根据指定的key获取对应的属性值,如果获取不到则返回默认值{@code defaultValue}* @param key 要解析的属性名* @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);/*** 根据指定的key获取对应的属性值,并把该属性值转换为{@code targetType}并返回* @param key 要解析的属性名* @param targetType the expected type of the property value* @see #getRequiredProperty(String, Class)*/@Nullable<T> T getProperty(String key, Class<T> targetType);/*** 根据指定的key获取对应的属性值,如果为空则返回{@code defaultValue},如果不为空则并把该属性值转换为{@code targetType}并返回* @param key 要解析的属性名* @param targetType 期望转换的类型* @param defaultValue 默认值* @see #getRequiredProperty(String, Class)*/<T> T getProperty(String key, Class<T> targetType, T defaultValue);/*** 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;/*** 对指定的文本进行占位符的解析* @param text 要解析的文本* @return 解析占位符后的文本* @throws IllegalArgumentException if given text is {@code null}* @see #resolveRequiredPlaceholders*/String resolvePlaceholders(String text);String resolveRequiredPlaceholders(String text) throws IllegalArgumentException;

ConfigurablePropertyResolver

java">/*** 该接口继承于{@link PropertyResolver},开放了对属性解析器的一些配置方法,* 并且增加了支持对属性进行类型装换的功能{@link ConversionService}** @author Chris Beams* @since 3.1*/
public interface ConfigurablePropertyResolver extends PropertyResolver {/*** 获取类型转换器* @see PropertyResolver#getProperty(String, Class)* @see org.springframework.core.convert.converter.ConverterRegistry#addConverter*/ConfigurableConversionService getConversionService();/*** 设置一个类型转换器* @see PropertyResolver#getProperty(String, Class)* @see #getConversionService()* @see org.springframework.core.convert.converter.ConverterRegistry#addConverter*/void setConversionService(ConfigurableConversionService conversionService);/*** 设置解析的占位符前缀*/void setPlaceholderPrefix(String placeholderPrefix);/*** 设置解析的占位符后缀*/void setPlaceholderSuffix(String placeholderSuffix);/*** 设置解析的占位符与其关联的默认值之间的分隔字符*/void setValueSeparator(@Nullable String valueSeparator);/*** 设置遇到嵌套在给定属性值内的无法解析占位符时是否引发异常。* {@code false}值表示严格的解析,即将抛出异常。{@code true}值表示不可解析的嵌套占位符应以其未解析的${…}形式传递。* @since 3.2*/void setIgnoreUnresolvableNestedPlaceholders(boolean ignoreUnresolvableNestedPlaceholders);void setRequiredProperties(String... requiredProperties);void validateRequiredProperties() throws MissingRequiredPropertiesException;

可以看到ConfigurablePropertyResolver接口继承自PropertyResolver接口,增加了一些set方法,这些方法都是对属性解析的时候需要的,比如解析的占位符是什么,默认值的分割字符是什么,属性转换器的设置等等

ConversionService

属性类型转换器,这个组件为啥会和Envirnoment有关呢?举个例子,比如说有一个属性key是user.id,而这个key对应的属性值则是1,2,3这样的字符串,如果我们根据user.id去获取那么得到的肯定就是一个字符串对吧,但是如果我们想要得到的是一个list呢?那么就需要对1,2,3这个字符串去进行分割然后加入到一个list中返回了,那么这个过程就需要类型转换器去负责了,因此类型转换器有很多种,我们也可以自定义类型转换器

Environment

作为Spring环境配置的顶级接口,其继承自PropertyResolver(为什么要继承该接口?上面已经说了),该接口下定义的方法如下:

java">/*** 返回所有被激活的配置环境,可以通过{@link ConfigurableEnvironment#setActiveProfiles(java.lang.String...)}方法* 去设置要激活的配置环境,设置的key需要是{@link AbstractEnvironment#ACTIVE_Profiles_PROPERTY_NAME}* @see #getDefaultProfiles* @see ConfigurableEnvironment#setActiveProfiles* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME*/
String[] getActiveProfiles();/*** 返回所有默认的配置环境(当没有设置要激活的配置环境的时候就使用默认的配置环境)* @see #getActiveProfiles* @see ConfigurableEnvironment#setDefaultProfiles* @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME*/
String[] getDefaultProfiles();/*** 判断传进来的这些profiles是否都是被激活的* @see #getActiveProfiles* @see #getDefaultProfiles* @see #acceptsProfiles(Profiles)* @deprecated as of 5.1 in favor of {@link #acceptsProfiles(Profiles)}*/
@Deprecated
boolean acceptsProfiles(String... profiles);/*** 判断传进来的profile是否是被激活的*/
boolean acceptsProfiles(Profiles profiles);

可以看到Environment接口下定义的方法都是与profile有关

ConfigurableEnvironment

在Environment接口的基础上新增了一些setXXX的方法,使得整个环境组件是可配置的

java">/*** 设置要激活的配置环境* @throws IllegalArgumentException if any profile is null, empty or whitespace-only* @see #addActiveProfile* @see #setDefaultProfiles* @see org.springframework.context.annotation.Profile* @see AbstractEnvironment#ACTIVE_PROFILES_PROPERTY_NAME*/
void setActiveProfiles(String... profiles);/*** 添加一个要激活的配置环境* @throws IllegalArgumentException if the profile is null, empty or whitespace-only* @see #setActiveProfiles*/
void addActiveProfile(String profile);/*** 设置默认的配置环境* @throws IllegalArgumentException if any profile is null, empty or whitespace-only* @see AbstractEnvironment#DEFAULT_PROFILES_PROPERTY_NAME*/
void setDefaultProfiles(String... profiles);MutablePropertySources getPropertySources();Map<String, Object> getSystemProperties();Map<String, Object> getSystemEnvironment();void merge(ConfigurableEnvironment parent);

比如设置要激活的profile,设置默认的profile,获取系统环境变量,合并另外的Environment等

AbstractEnvironment

抽象的Environment实现,继承自ConfigurableEnvironment接口,统一实现了

ConfigurableEnvironment里面的方法

我们主要关注下里面的几个关键属性:

java">/*** 被激活的配置环境名称集合*/
private final Set<String> activeProfiles = new LinkedHashSet<>();/*** 默认的配置环境名称集合*/
private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles());/*** PropertySource集合*/
private final MutablePropertySources propertySources = new MutablePropertySources();/*** 属性解析器,它能够去解析占位符并且进行类型转换*/
private final ConfigurablePropertyResolver propertyResolver = new PropertySourcesPropertyResolver(this.propertySources);

当然还有它的构造方法:

java">public AbstractEnvironment() {customizePropertySources(this.propertySources);
}

在构造方法中会去调用customizePropertySources方法,并把属性源集合作为参数传递进去,而customizePropertySources方法则是个空方法,交由子类去进行扩展,如果子类有自己的一些属性源想放到Environment中的话就可以去进行重写并把自己的属性源放到传入的属性源参数中,比如StandardEnvironment就重写了该方法去添加系统环境变量的属性源以及JVM环境配置的属性源

StandardEnvironment

一个标准的Environment实现,使用该实现则可以获取到系统环境变量以及JVM运行时信息的属性源

java">public class StandardEnvironment extends AbstractEnvironment {/*** 系统环境的属性源名称,这个获得是一些系统环境变量,比如用户配置的一些路径信息*/public static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";/*** 系统级别的属性源名称,和上面不同的是,这个可以获得JAVA运行时的一些信息,比如JVM的一些信息*/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()*/@Overrideprotected void customizePropertySources(MutablePropertySources propertySources) {// 添加系统变量propertySources.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));// 添加环境变量propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));}}

http://www.ppmy.cn/embedded/128519.html

相关文章

程序员转行方向推荐

对于程序员转行方向的推荐&#xff0c;可以基于当前的技术趋势、市场需求以及程序员的个人技能和兴趣来综合考虑。以下是一些推荐的转行方向&#xff1a; 伴随着社会的发展&#xff0c;网络安全被列为国家安全战略的一部分&#xff0c;因此越来越多的行业开始迫切需要网安人员…

20201017-【C、C++】跳动的爱心

效果图片 代码 #include "graphics.h" #include <conio.h> #include <time.h> #include <math.h> #include <stdlib.h>struct Point {double x, y;COLORREF color; };COLORREF colors[256] {RGB(255,32,83),RGB(252,222,250),RGB(255,0,0)…

2012年国赛高教杯数学建模D题机器人避障问题解题全过程文档及程序

2012年国赛高教杯数学建模 D题 机器人避障问题 图1是一个800800的平面场景图&#xff0c;在原点O(0, 0)点处有一个机器人&#xff0c;它只能在该平面场景范围内活动。图中有12个不同形状的区域是机器人不能与之发生碰撞的障碍物&#xff0c;障碍物的数学描述如下表&#xff1a…

简单说说 spring 是如何处理循环依赖问题的(源码解析)

聊聊源码 在spring 中&#xff0c;解决循环依赖的关键是三级缓存&#xff0c;缓存数据在 DefaultSingletonBeanRegistry类中 /** Cache of singleton objects: bean name to bean instance. */ //一级缓存&#xff0c;是最终生成的对象 private final Map<String, Object&…

数据结构——树和森林

目录 树的存储结构 1、双亲表示法 2、孩子链表 3、孩子兄弟表示法 树与二叉树的转换 将树转换为二叉树 将二叉树转换为树 森林与二叉树的转化 森林转换成二叉树 二叉树转换为森林 树和森林的遍历 1、 树的遍历&#xff08;三种方式&#xff09; 2、森林的遍历 树的存…

linux的学习第二天

1.vmware的功能&#xff1a; 快照 创建快照&#xff1a; 拍摄此虚拟机的快照&#xff1a;记录保存虚拟机的当前状态&#xff0c;如果系统出现故障&#xff0c;可以通过快照还原&#xff08;错删系统时可以找到快照的系统状态&#xff0c;然后恢复系统&#xff09; 恢复快照…

2024.10月11日--- SpringMVC拦截器

拦截器 1 回顾过滤器&#xff1a; Servlet规范中的三大接口&#xff1a;Servlet接口&#xff0c;Filter接口、Listener接口。 过滤器接口&#xff0c;是Servlet2.3版本以来&#xff0c;定义的一种小型的&#xff0c;可插拔的Web组件&#xff0c;可以用来拦截和处理Servlet容…

计算机毕设选题推荐【大数据专业】

计算机毕设选题推荐【大数据专业】 大数据专业的毕业设计需要结合数据的采集、存储、处理与分析等方面的技能。为帮助同学们找到一个适合且具有实践性的选题&#xff0c;我们为大家整理了50个精选的毕设选题。这些选题涵盖了大数据分析、处理技术、可视化等多个方向&#xff0…