Spring Boot - 扩展点 EnvironmentPostProcessor源码分析及真实案例

文章目录

  • 概述
  • EnvironmentPostProcessor 作用
  • EnvironmentPostProcessor 实现和注册
    • 创建类并实现接口
    • 注册到 Spring Boot
    • 常见应用场景
  • 源码分析
    • 1. `EnvironmentPostProcessor` 接口定义
    • 2. 扩展点加载流程
    • 3. 加载 `EnvironmentPostProcessor` 实现类
    • 4. `EnvironmentPostProcessor` 执行时机
    • 5. 环境属性源的扩展示例
    • 6. `EnvironmentPostProcessor` 应用场景
  • 真实案例
  • 小结

在这里插入图片描述


概述

EnvironmentPostProcessor 是 Spring Boot 提供的一个扩展点,用于在应用环境初始化过程中执行一些额外的处理。该接口允许开发者在 Spring Environment 初始化完成后、应用上下文加载之前,自定义和调整环境变量,这为配置和条件化应用设置提供了极大的灵活性。


EnvironmentPostProcessor 作用

EnvironmentPostProcessor 作为一个接口,允许在 Spring Environment 对象被创建和配置后进行扩展操作。通过它,可以在应用启动时添加、修改或删除 Environment 中的属性值,比如注入额外的配置源、动态设置配置项、调整日志级别等。

使用场景

  • 自定义配置源,例如从数据库或远程服务动态加载配置。
  • 修改现有的配置值,或基于环境动态调整配置。
  • 执行一些特定逻辑,如根据某些条件禁用部分功能或切换日志级别。

EnvironmentPostProcessor 实现和注册

创建类并实现接口

实现 EnvironmentPostProcessor 接口的类,需要重写其 postProcessEnvironment 方法,在该方法中注入或修改环境配置。

import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import java.util.HashMap;
import java.util.Map;public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {@Overridepublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {Map<String, Object> customProperties = new HashMap<>();customProperties.put("custom.property", "customValue");environment.getPropertySources().addFirst(new MapPropertySource("customProperties", customProperties));}
}

注册到 Spring Boot

CustomEnvironmentPostProcessor 注册为一个 EnvironmentPostProcessor,通过在 META-INF/spring.factories 文件中添加如下配置:

org.springframework.boot.env.EnvironmentPostProcessor=\
com.example.CustomEnvironmentPostProcessor

Spring Boot 会自动扫描 spring.factories 中的定义,并在环境初始化时加载 CustomEnvironmentPostProcessor


常见应用场景

  • 动态配置加载:可在启动时通过读取外部配置源(如数据库、远程服务)来加载配置。
  • 条件化配置注入:基于环境条件,动态插入某些配置项。
  • 日志配置:在应用启动时根据外部条件设置日志级别或日志输出位置。
  • 多环境支持:可以根据当前环境(如 dev、prod)注入不同的默认配置。

源码分析

1. EnvironmentPostProcessor 接口定义

EnvironmentPostProcessor 是一个非常简单的接口,仅包含一个方法 postProcessEnvironment。下面是其接口的定义:

package org.springframework.boot.env;import org.springframework.boot.SpringApplication;
import org.springframework.core.env.ConfigurableEnvironment;@FunctionalInterface
public interface EnvironmentPostProcessor {void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application);
}
  • 参数解释

    • ConfigurableEnvironment environment:当前 Spring 应用的 Environment 对象,通过该参数可以访问和操作环境中的属性源。
    • SpringApplication application:Spring 应用的入口,提供对应用的一些基本信息和配置信息的访问。
  • 注解@FunctionalInterface 表明它是一个函数式接口,可以用 lambda 表达式实现。


2. 扩展点加载流程

在 Spring Boot 应用启动时,SpringApplication 类负责初始化并加载一系列的配置扩展点,EnvironmentPostProcessor 也是在此阶段被加载的。SpringApplication 会在初始化过程中,使用 SpringFactoriesLoaderMETA-INF/spring.factories 文件中加载所有注册的 EnvironmentPostProcessor 实现。

关键代码在 SpringApplication 类的 configureEnvironment 方法中:

// SpringApplication.java 中
private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, ApplicationArguments applicationArguments) {// 创建并配置环境ConfigurableEnvironment environment = this.getOrCreateEnvironment();// 配置 Environment,包括加载 EnvironmentPostProcessorthis.configureEnvironment(environment, applicationArguments.getSourceArgs());listeners.environmentPrepared(environment);// 绑定环境属性并返回return environment;
}

configureEnvironment 方法中,会调用 applyInitializers 方法,加载所有的 ApplicationContextInitializerEnvironmentPostProcessor 实现。

3. 加载 EnvironmentPostProcessor 实现类

SpringFactoriesLoader 是 Spring 的一个通用加载工具,用于从 META-INF/spring.factories 文件中读取配置类并实例化。Spring Boot 使用 SpringFactoriesLoader 来加载 EnvironmentPostProcessor 实现类,并在应用启动时逐一执行它们的 postProcessEnvironment 方法。

// SpringApplication.java 中
private void applyInitializers(ConfigurableApplicationContext context) {List<ApplicationContextInitializer<?>> initializers = getInitializers();for (ApplicationContextInitializer<?> initializer : initializers) {if (initializer instanceof EnvironmentPostProcessor) {((EnvironmentPostProcessor) initializer).postProcessEnvironment(context.getEnvironment(), this);}}
}

排序执行: Spring Boot 会将所有找到的 EnvironmentPostProcessor 实现按照 @Order 注解或实现 Ordered 接口的方式进行排序,然后依次执行它们的 postProcessEnvironment 方法


4. EnvironmentPostProcessor 执行时机

EnvironmentPostProcessorpostProcessEnvironment 方法会在应用上下文 ApplicationContext 初始化之前被调用。也就是说,在加载应用的 @Bean 和其他上下文配置之前,EnvironmentPostProcessor 已经对环境进行了处理。

此调用顺序确保开发者可以在应用加载所有属性和资源文件之前,修改环境变量或添加新的属性源。这对动态配置源或在运行时确定属性值的场景特别有用。

修改 Environment: 在 postProcessEnvironment 方法中,可以通过 ConfigurableEnvironment 对象操作应用的环境。最常见的操作是添加自定义的 PropertySource,例如从数据库或配置文件中读取属性

5. 环境属性源的扩展示例

假设我们希望在环境中加入一个自定义配置,可以通过 EnvironmentPostProcessor 来实现:

public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {@Overridepublic void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {// 创建一个自定义属性源Map<String, Object> customProperties = new HashMap<>();customProperties.put("custom.property", "customValue");// 将自定义属性源添加到环境中environment.getPropertySources().addFirst(new MapPropertySource("customProperties", customProperties));}
}

6. EnvironmentPostProcessor 应用场景

  • 动态属性注入:在应用启动时从数据库或外部服务获取配置,并将其添加到 Environment 中。
  • 基于环境的配置:根据当前环境变量(如 devprod)动态设置不同的配置。
  • 日志配置:通过 EnvironmentPostProcessor 可以在应用启动前修改日志级别或日志文件路径。

真实案例

小结

Spring Boot 的 EnvironmentPostProcessor 提供了在应用启动过程中的一个灵活扩展点,适用于有定制配置需求的场景。通过实现该接口,开发者可以在 Spring 应用上下文创建前调整环境配置,提供更强的动态控制和灵活性。

  • EnvironmentPostProcessor 是 Spring Boot 中的一个早期扩展点,允许开发者在 Environment 初始化之后、ApplicationContext 初始化之前操作环境。
  • Spring Boot 使用 SpringFactoriesLoaderMETA-INF/spring.factories 文件中加载 EnvironmentPostProcessor 实现。
  • 此扩展点适合用于动态加载配置、基于环境修改配置等场景。

通过 EnvironmentPostProcessor,开发者可以在 Spring Boot 应用启动的早期阶段,实现对应用环境的自定义配置,以满足特定的需求。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

封装的数字滚动组件的实现代码

效果&#xff1a; 学习啦&#xff1a; Vue 是一个渐进式框架&#xff0c;鼓励通过组件化来构建应用&#xff0c;其组件化优势&#xff1a; 代码复用&#xff1a;不同的视图和功能被封装成独立的组件&#xff0c;便于复用。易于维护&#xff1a;每个组件职责单一、耦合度低&…

Unity跨平台基本原理

目录 前言 ​编辑 Mono Unity和Mono的关系 Unity跨平台必备概念 Mono利用 Mono主要构成部分 基于Mono跨平台的优缺点 IL2CPP Mono和IL2CPP的区别 Mono IL2CPP Mono和IL2CPP的使用建议 安装IL2CPP IL2CPP打包存在的问题 类型裁剪 泛型问题 前言 Unity跨平台的基…

计算机网络(3)

UDP是面向无连接的通信协议&#xff0c;UDP数据包括目的端口号和源端口号信息&#xff0c;由于 不需要连接&#xff0c;所以可以实现广播发送&#xff1b; 传输控制层 UDP协议&#xff08;用户数据报协议&#xff09; UDP通信时不需要接收方确认&#xff0c;属于不可靠的传输&a…

2024年11月8日上海帆软用户大会

2024年11月8日上海帆软用户大会 2024年11月8日&#xff0c;上海成功举办了帆软用户大会&#xff0c;主题为“数字聚力&#xff0c;绽放新机”。大会汇聚了众多行业专家和企业代表&#xff0c;共同探讨数字化转型和商业智能领域的最新趋势和实践。 大会亮点&#xff1a; 专家…

PySimpleGUI和Pymysql

PySimpleGUI 库 PySimpleGUI 是一个用于简化 GUI 编程的 Python 包&#xff0c;它封装了多种底层 GUI 框架&#xff08;如 tkinter、Qt、WxPython 等&#xff09;&#xff0c;提供了简单易用的 API。PySimpleGUI 包含了大量的控件&#xff08;也称为小部件或组件&#xff09;&…

Qt Event事件系统小探1

目录 Qt Event System From qt.doc 如何传递事件 事件类型 事件处理程序 事件过滤器 发送事件 事件的产生和派发 处理我们的事件 来一段好玩的代码 扩展&#xff1a;QWidget如何处理我们的事件&#xff1f; 扩展2&#xff1a;实现一个变色的Label Qt Event System Fr…

文章解读与仿真程序复现思路——电网技术EI\CSCD\北大核心《基于凸多面体仿射变换的用户侧灵活性资源多元聚合方法》

本专栏栏目提供文章与程序复现思路&#xff0c;具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

vue3组合式API下封装hooks使用生命周期,在await之后调用hooks会有警告

起因&#xff1a;想封装一个hooks实现echarts图表随屏幕大小resize并且组件销毁时移除监听。结果在组件里面调用这个hooks&#xff0c;有个告警提示 [Vue warn]: onBeforeUnmount is called when there is no active component instance to be associated with. Lifecycle inje…

使用Python实现图像的手绘风格效果

使用Python实现图像的手绘风格效果 一、引言二、代码详细解释与示例三、完整框架流程四、运行五、结论附&#xff1a;完整代码 一、引言 在数字图像处理领域&#xff0c;模拟手绘风格是一项有趣且具有挑战性的任务。手绘风格图像通常具有独特的纹理和深浅变化&#xff0c;给人…

window中借助nginx配置vite+vue项目的反向代理步骤

在官网下载好nginx的安装包后&#xff0c;解压后 CMD打开 start nginx 是启动命令 nginx -s stop 停止服务 nginx -s reload 如果重写了nginx.conf文件&#xff0c;要执行这条命令 正常情况下 成功启动和成功停止服务长这样 错误情况&解决 如果nginx -s stop失败 ngi…

花指令例子

如图所示&#xff1a; 指令EB FF的汇编代码为jmp -1&#xff0c;CPU执行到地址处0x6c80c0的指令EB FF时(jmp -1)&#xff0c;EIP为6c80c2, 执行后&#xff0c;EIP为0x6c80c1。但是反汇编器无法自动识别该指令。

关于我的编程语言——C/C++——第八篇

&#xff08;叠甲&#xff1a;如有侵权请联系&#xff0c;内容都是自己学习的总结&#xff0c;一定不全面&#xff0c;仅当互相交流&#xff08;轻点骂&#xff09;我也只是站在巨人肩膀上的一个小卡拉米&#xff0c;已老实&#xff0c;求放过&#xff09; 什么是C C语言是结…

博客园美化

1、主题介绍 使用的 SimpleMemory 这款主题 github官网 2、设置主题并申请 js 代码权限 3、主题设置 博客侧边栏公告 <script type"text/javascript">window.cnblogsConfig {info: {blogIcon: https://ts1.cn.mm.bing.net/th/id/R-C.85775e482741cb7ab7f…

SpringBoot基础系列学习(二):配置详解

文章目录 一丶依赖二丶配置文件三丶获取配置文件中的信息1.PropertySource("classpath:application2.properties")2. ConfigurationProperties(prefix "baicaizhi1")3. Value4. 使用EnviromentgBean获取5. 使用ResourceBundle获取 一丶依赖 <dependen…

初识Electron 进程通信

概述 Electron chromium nodejs native API&#xff0c;也就是将node环境和浏览器环境整合到了一起&#xff0c;这样就构成了桌面端&#xff08;chromium负责渲染、node负责操作系统API等&#xff09; 流程模型 预加载脚本&#xff1a;运行在浏览器环境下&#xff0c;但是…

建网站怎么建?只需几个步骤

在这个网络飞速发展的时代&#xff0c;越来越多的人都渴望拥有自己的网站。然而&#xff0c;对于大多数新手来说&#xff0c;如何建立自己的网站可能充满了挑战。本文将为您详细介绍建网站的关键步骤&#xff0c;让您能够轻松搭建自己的网站。 选择适合的建站工具 虽然市面上有…

台达控制器与三菱变频器实现EtherCAT转CC-Link IEFB协议通讯方案

一.项目背景&#xff1a; 在某自动化生产车间中&#xff0c;原有系统采用台达的 EtherCAT 控制器来控制多个设备的运动和操作&#xff0c;但车间内的一些关键设备使用的是三菱变频器&#xff0c;且基于 CC-Link IEFB 协议通讯。为了实现整个系统的集中控制和数据统一管理&#…

Js — 防抖及底层实现

防抖&#xff1a;单位时间内&#xff0c;频繁触发事件&#xff0c;只执行最后一次 防抖实现方式&#xff1a; lodash提供的防抖函数_.debounce(func,[wait0],[option]) 延迟wait毫秒后调用func方法 定时器setTimeout 目标&#xff1a;鼠标在盒子上移动&#xff0c;鼠标停止50…

负载均衡式在线oj项目开发文档2(个人项目)

judge模块的框架 完成了网页渲染的功能之后&#xff0c;就需要判断用户提交的代码是否是正确的&#xff0c;当用户点击提交之后&#xff0c;就会交给路由模块的/judge模块&#xff0c;然后这个路由模块就需要去调用jude模块了&#xff0c;也就是需要一个新的jude模块&#xff…

setContentView调用流程(二) -将布局添加到mContentParent

Android setContentView执行流程(一)-生成DecorView Android setContentView执行流程(二)-将布局添加到mContentParent 上篇博客我们介绍了setContentView的第一步即生成DecorView以及获取到mContentParent的流程&#xff0c;同时还提到继承自Activity和AppCompatActivity生成…