Spring 中的 Environment 对象

可参考官网:Environment Abstraction

核心概念

Environment 对象对两个关键方面进行建模:profiles 和 属性(properties)。

Profile

简单来说:profile 机制在 IOC 容器中提供了一种机制:允许在不同的环境中注册不同的bean。即对于一个bean,如果你想在情况A中注册它的一种类型,而在情况B中注册另一种类型,这时你就可以使用 profile

使用 @Profile

考虑一下实际应用,我们需要一个 DataSource。在 开发环境 中,我们希望IOC容器中它的类型是 DataSourceImpl1,而在 生产环境 中,我们希望IOC容器中它的类型是 DataSourceImpl2。
我们可以定义如下两个配置类:

@Configuration
@Profile("development")
public class DevelopmentDataConfig {@Beanpublic DataSource dataSource1() {return new DataSourceImpl1(); // 伪代码}
}@Configuration
@Profile("production") 
public class ProductionDataConfig {@Beanpublic DataSource dataSource2() {return new DataSourceImpl2(); // 伪代码}
}

@Profile 注解可以在 @Bean 方法上使用

激活一个 Profile
激活一个 profile 可以通过几种方式进行,但最直接的是 以编程方式 对环境API进行激活,该API可以通过 ApplicationContext 获得。下面的例子显示了如何做到这一点:

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("development"); // 激活 "development" 对应的 profile(可以指定多个)
ctx.register(AppConfig.class, DevelopmentDataConfig.class, ProductionDataConfig.class); 
ctx.refresh();

此外,你还可以通过 spring.profiles.active 属性以声明方式激活配置文件,该属性可以通过 系统环境变量、JVM 系统属性、web.xml 中的 servlet 上下文参数这些参数其实都会以 “属性源PropertySource” 的形式保存在 Environment 中,包括 SpringBoot 应用中 yml 中配置的参数) 来指定

如,通过 JVM系统属性指定:

-Dspring.profiles.active="development"   #可以指定多个profile

这样一来,IOC 容器在启动时,就会注入 development 环境所需要的 DataSourceImpl1 bean对象

默认 Profile
如果没有活动的 profile,那么 Spring 底层会启用默认的 profile(“default”)

@Configuration
@Profile("default") // 系统默认会启用"default"对应的profile
public class DefaultDataConfig {@Beanpublic DataSource dataSource() {return new DataSourceImpl3();}
}

以上配置表明:即使你没有激活任何 profile ,DataSourceImpl3 也会被注入到容器中

如果任何 profile 被启用,默认的profile就不应用。
你可以通过在环境中使用 setDefaultProfiles() 来改变默认配置文件的名称,或者通过声明性地使用 spring.profiles.default 属性。

属性(properties)

在 Spring 中,使用 PropertySource 对象对属性进行抽象。PropertySource 是对 “任何键值对源” 的简单抽象,提供了统一存储外部化配置数据的功能,例如上面配置的JVM系统属性就会被封装为 PropertySource 对象(可参考其 javadoc)

Environment 对象中保存了一系列 PropertySource 集合,可以使用 Environment 对 PropertySource 进行搜索获取:

ApplicationContext ctx = new GenericApplicationContext();
Environment env = ctx.getEnvironment();
boolean flag = env.containsProperty("my-property");
System.out.println(flag); // 当前环境中是否定义了 my-property 属性?

Spring 的 StandardEnvironment 对象保存了两个 PropertySource 对象—— 一个表示 JVM 系统属性集合(System.getProperties()),另一个表示系统环境变量集合(System.getenv())

这些默认属性源存在于 StandardEnvironment 中,用于独立的应用程序中。
而其子类 StandardServletEnvironment 中填充了其他默认属性源,包括 Servlet config、Servlet context 参数和 JndiPropertySource(如果 JNDI 可用)。

执行的搜索是分层次的。默认情况下,系统属性(system properties)优先于环境变量(environment variables)
因此,如果在调用 env.getProperty(“my-property”) 时,my-property 属性恰好在两个地方都被设置了,那么系统属性值 “胜出” 并被返回。请注意,属性值不会合并,而是被前面的条目完全覆盖。

我们可以定义自己的 PropertySource 加入到当前 Environment 中,并且可以指定其位置(搜索优先级)

ConfigurableApplicationContext ctx = new GenericApplicationContext();
MutablePropertySources sources = ctx.getEnvironment().getPropertySources();
sources.addFirst(new MyPropertySource());  // 加入到最前面(优先级最高)



源码解析

先看 Environment 的体系架构:
在这里插入图片描述

我们可以从 AbstractEnvironment 类入手:

当一个组件Xxx(接口)体系很复杂时,从它具体的落地实现类开始分析是十分复杂的,可以考虑从它的抽象实现类:AbstractXxx 入手(内部一定定义了某些重要方法的抽象实现,和一些重要的成员属性)

AbstractEnvironment 中几个比较重要的成员属性:

private final Set<String> activeProfiles = new LinkedHashSet<>(); // 保存激活的Profile
private final Set<String> defaultProfiles = new LinkedHashSet<>(getReservedDefaultProfiles()); // 保存默认的 Profile
private final MutablePropertySources propertySources;   // 存放一系列 PropertySource
private final ConfigurablePropertyResolver propertyResolver; // 属性解析器(如解析占位符${})

其中 MutablePropertySources 对象维护着一个 PropertySource 列表,外部可以通过 get、contains、addFirst 等方法对其进行访问

对外暴露的与 profile 相关的 API 方法(可自行查看方法内部逻辑):

getDefaultProfiles(); // 获取默认的 Profile
setDefaultProfiles(); // 设置默认的 Profile
getActiveProfiles(); // 获取激活的 Profile
setActiveProfiles(); // 设置激活的 Profile

所以说:Environment 对象对两个关键方面进行建模:Profile 和 PropertySource(属性源)

当我们使用 SpringBoot 进行传统的 Web 开发时,应用环境为 SERVLET ,默认使用的 Environment 实现为:ApplicationServletEnvironment

源码位置:run() —> prepareEnvironment() —> getOrCreateEnvironment()

	private ConfigurableEnvironment getOrCreateEnvironment() {if (this.environment != null) {return this.environment;}switch (this.webApplicationType) {case SERVLET:return new ApplicationServletEnvironment();case REACTIVE:return new ApplicationReactiveWebEnvironment();default:return new ApplicationEnvironment();}}

就是直接使用无参构造创建其对象:new ApplicationServletEnvironment(),分析这个动作都发生了什么

ApplicationServletEnvironment 的无参构造中会调父类的无参构造(默认有super.())… 一直会调用到 AbstractEnvironment 的无参构造:

public AbstractEnvironment() {this(new MutablePropertySources()); 
}protected AbstractEnvironment(MutablePropertySources propertySources) {this.propertySources = propertySources; // 新 new 的 MutablePropertySourcesthis.propertyResolver = createPropertyResolver(propertySources);customizePropertySources(propertySources); // 模板方法,提供给子类实现(子类向propertySources里面添加一些PropertySource)
}

套路:在分析父类预留给子类实现的方法时,要定位到此方法 “最后一次的重写位置”

子类 StandardServletEnvironment # customizePropertySources 的实现:(customizePropertySources 方法最后的重写位置(StandardServletEnvironment 一系中))

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {// 向 propertySources 中加入了几个 PropertySource :"servletConfigInitParams"、"servletContextInitParams"、"jndiProperties"(根据情况) propertySources.addLast(new StubPropertySource(SERVLET_CONFIG_PROPERTY_SOURCE_NAME));propertySources.addLast(new StubPropertySource(SERVLET_CONTEXT_PROPERTY_SOURCE_NAME));if (jndiPresent && JndiLocatorDelegate.isDefaultJndiEnvironmentAvailable()) {propertySources.addLast(new JndiPropertySource(JNDI_PROPERTY_SOURCE_NAME));}// 回调父类 StandardEnvironment # customizePropertySources (父类 StandardEnvironment再向propertySources中加入几个PropertySource)super.customizePropertySources(propertySources);
}

StandardEnvironment # customizePropertySources

@Override
protected void customizePropertySources(MutablePropertySources propertySources) {// 向 propertySources 中加入了几个 PropertySource :"systemProperties"、"systemEnvironment"propertySources.addLast(new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));propertySources.addLast(new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

所以在 ApplicationServletEnvironment 对象创建完成之后,它所持有的 propertySources 中至少保存了 “servletContextInitParams”、“servletConfigInitParams”、“systemEnvironment”、“systemProperties” 四个 PropertySource

(待…)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/465063.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文速读】Optimization-based Prompt Injection Attack to LLM-as-a-Judge

基于优化的提示词注入攻击 摘要引言问题描述LLM-as-a-judge威胁模型攻击者知道什么 JUDGEDECEIVER 细节概述生成影子候选回复公式化为优化问题Target-aligned generation lossTarget-enhancement lossAdversarial perplexity loss优化问题 求解优化问题 摘要 LLM-as-a-Judge 利…

qt QStandardItem详解

1、概述 QStandardItem是Qt框架中QStandardItemModel的一个基础元素&#xff0c;用于在基于项的模型&#xff08;如QStandardItemModel&#xff09;中表示单个数据项。QStandardItem可以存储文本、图标、工具提示等丰富的信息&#xff0c;并且支持数据的编辑和自定义显示。通过…

戴尔电脑 Bios 如何进入?Dell Bios 进入 Bios 快捷键是什么?

BIOS&#xff08;基本输入输出系统&#xff09;是计算机启动时运行的第一个程序&#xff0c;它负责初始化硬件并加载操作系统。对于戴尔电脑用户来说&#xff0c;有时可能需要进入 BIOS 进行一些特定的设置调整&#xff0c;比如更改启动顺序、调整性能选项或解决硬件兼容性问题…

低代码解锁跨平台应用开发新境界

数字化转型中&#xff0c;企业面临应用开发挑战&#xff0c;低代码平台成为理想选择。ZohoCreator提供统一开发环境、拖拽设计、预置模板等&#xff0c;支持高效构建跨平台应用&#xff0c;确保数据安全与合规&#xff0c;助力企业数字化转型。 一、低代码平台是什么&#xff1…

`掌握Python-PPTX,让PPt制作变得轻而易举!`

文章目录 掌握Python-PPTX&#xff0c;让PPT制作变得轻而易举&#xff01;背景介绍python-pptx 是什么&#xff1f;如何安装 python-pptx&#xff1f;简单库函数使用方法应用场景常见Bug及解决方案总结 掌握Python-PPTX&#xff0c;让PPT制作变得轻而易举&#xff01; 背景介绍…

【含文档+源码】基于SpringBoot+Vue的新型吃住玩一体化旅游管理系统的设计与实现

开题报告 本文旨在探讨新型吃住玩一体化旅游管理系统的设计与实现。该系统融合了用户注册与登录、旅游景点管理、旅游攻略发帖、特色旅游路线推荐、附近美食推荐以及酒店客房推荐与预定等多项功能&#xff0c;旨在为游客提供全方位、一体化的旅游服务体验。在系统设计中&#…

[C++]——哈希(附源码)

目录 ​编辑 ​编辑 一、前言 二、正文 2.1 unorder系列关联式容器 2.1.1 unordered_map 2.1.1.1 unorderer_map的介绍 ①unordered_map的构造 ②unordered_map的容量 ③unordered_map的迭代器 ④unordered_map的元素访问 ⑤unordered_map的查询 ⑥unordered_map的修改操…

Oracle视频基础1.4.5练习

1.4.5 看bbk的框架 ls env | grep ORA cd /u01/oradata ls ll cd bbk ll cd /u01/admin/ ll ll bbk cd cd db cd dbs ls vi initbbk.ora clear ls ll env | grep ORA执行创建数据库语句。 sqlplus /nolog conn /as sysdba create spfile from pfile ! ls ll exit startup nom…

Spring Boot 与 Vue 共筑高校网上订餐卓越平台

作者介绍&#xff1a;✌️大厂全栈码农|毕设实战开发&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 &#x1f345;获取源码联系方式请查看文末&#x1f345; 推荐订阅精彩专栏 &#x1f447;&#x1f3fb; 避免错过下次更新 Springboot项目精选实战案例 更多项目…

【设计模式系列】建造者模式(十)

目录 一、什么是建造者模式 二、建造者模式的角色 三、建造者模式的典型应用 四、建造者模式在StringBuilder中的应用 五、典型建造者模式的案例 一、什么是建造者模式 建造者模式&#xff08;Builder Pattern&#xff09;是一种创建型设计模式&#xff0c;用于构建复杂对…

H7-TOOL的LUA小程序教程第17期:扩展驱动AD7606, ADS1256,MCP3421, 8路继电器和5路DS18B20(2024-11-01)

LUA脚本的好处是用户可以根据自己注册的一批API&#xff08;当前TOOL已经提供了几百个函数供大家使用&#xff09;&#xff0c;实现各种小程序&#xff0c;不再限制Flash里面已经下载的程序&#xff0c;就跟手机安装APP差不多&#xff0c;所以在H7-TOOL里面被广泛使用&#xff…

P10 Pytorch入门实战——Pytorch实现车牌识别

一、前期准备 1. 设置device # import the necessary libraries import torch import torch.nn as nn import torchvision.transforms as transforms from torchvision import transforms, datasets import matplotlib.pyplot as plt import PIL,pathlib from PIL import Im…

基于SSM+小程序的宿舍管理系统(宿舍1)

&#x1f449;文末查看项目功能视频演示获取源码sql脚本视频导入教程视频 1、项目介绍 本宿舍管理系统小程序有管理员和学生两个角色。 1、管理员功能有个人中心&#xff0c;公告信息管理&#xff0c;班级管理&#xff0c;学生管理&#xff0c;宿舍信息管理&#xff0c;宿舍…

基于 JavaWeb 的宠物商城系统(附源码,文档)

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

.NET周刊【11月第1期 2024-11-03】

国内文章 .NET 9 AOT的突破 - 支持老旧Win7与XP环境 https://www.cnblogs.com/lsq6/p/18519287 .NET 9 引入了 AOT 支持&#xff0c;使得应用程序能够在编译时优化&#xff0c;以在老旧 Windows 系统上运行。这项技术通过静态编译&#xff0c;消除运行时的 JIT 编译&#xf…

iptables 规则备份和恢复

保存IPiptables规则 使用 service 命令: 在 CentOS 7 中&#xff0c;您可以使用 service 命令来保存当前的 iptables 规则&#xff1a; iptables save 这将把当前的 iptables 规则保存到 /etc/sysconfig/iptables 文件中。 使用 iptables-save 命令: 另一种方法是使用 iptab…

知乎信息流广告推广开户流程及攻略!

无论是品牌推广、产品营销还是获取精准流量&#xff0c;知乎信息流广告都能成为企业和营销者的有力武器。云衔科技作为专业的服务提供商&#xff0c;为企业提供知乎广告开户及代运营服务。 一、知乎信息流广告 知乎拥有海量的高质量用户&#xff0c;他们来自各行各业&#xf…

6-解决Ubuntu系统与Windows系统双系统时间不同步问题

引言 &#xff1a; 你是不是每次切换系统之后&#xff0c;系统时间就混乱了&#xff1f;想设置一致但又无从下手。看完这篇文章&#xff0c;你就全懂了&#xff01;&#xff01; 学习目标&#xff1a; 帮助开发者理解并解决 Ubuntu 与 Windows 双系统中时间不同步的问题。通…

【大数据学习 | kafka】kafka的偏移量管理

1. 偏移量的概念 消费者在消费数据的时候需要将消费的记录存储到一个位置&#xff0c;防止因为消费者程序宕机而引起断点消费数据丢失问题&#xff0c;下一次可以按照相应的位置从kafka中找寻数据&#xff0c;这个消费位置记录称之为偏移量offset。 kafka0.9以前版本将偏移量信…

基于梯度的快速准确头部运动补偿方法在锥束CT中的应用|文献速递-基于深度学习的病灶分割与数据超分辨率

Title 题目 A gradient-based approach to fast and accurate head motion compensation in cone-beam CT 基于梯度的快速准确头部运动补偿方法在锥束CT中的应用 01 文献速递介绍 锥束计算机断层扫描&#xff08;CBCT&#xff09;系统在灵活性方面比螺旋多排探测器计算机断…