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 {
    @Override
    public 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,包括加载 EnvironmentPostProcessor
    this.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 {
    @Override
    public 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 应用启动的早期阶段,实现对应用环境的自定义配置,以满足特定的需求。

在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【eNSP】企业网络架构链路聚合、数据抓包、远程连接访问实验(二)

一、实验目的 网络分段与VLAN划分&#xff1a; 通过实验了解如何将一个大网络划分为多个小的子网&#xff08;VLAN&#xff09;&#xff0c;以提高网络性能和安全性。 VLAN间路由&#xff1a; 学习如何配置VLAN间的路由&#xff0c;使不同VLAN之间能够通信。 网络设备配置&am…

Python 智取京东商品详情:代码秘籍大公开

介绍使用 Python 获取京东商品详情的背景和意义&#xff0c;强调其在数据收集和分析中的重要性。 &#xff08;一&#xff09;数据收集的需求 在当今数字化的商业环境中&#xff0c;对京东商品详情数据的需求日益增长。市场调研人员需要这些数据来了解不同产品的市场份额、价格…

[C++]——位图与布隆过滤器

目录 一、前言 二、正文 1.位图 1.1 位图概念 1.2 位图的实现 1.2.1 Set 1.2.2 ReSet 1.2.3 Text 1.3 位图的应用 2.布隆过滤器 2.1布隆过滤器的提出 2.2 布隆过滤器概念 2.3 布隆过滤器的实现 2.3.1布隆过滤器的插入 2.3.2 布隆过滤器的查找 2.3.3 布隆过滤器…

工具收集 - java-decompiler / jd-gui

工具收集 - java-decompiler / jd-gui 参考资料 用法&#xff1a;拖进来就行了 参考资料 https://github.com/java-decompiler/jd-gui 脚本之家&#xff1a;java反编译工具jd-gui使用详解

Spark的容错机制:persist持久化机制checkpoint检查点机制区别

persist持久化机制&#xff1a; 作用&#xff1a;将RDD的数据缓存到内存或磁盘中&#xff0c;以便在后续操作中重复使用&#xff0c;减少计算开销。特点&#xff1a; 灵活性高&#xff1a;可以指定不同的存储级别&#xff08;如仅内存、内存和磁盘、仅磁盘等&#xff09;。 数…

Elasticsearch集群和Kibana部署流程

搭建Elasticsearch集群 1. 进入Elasticsearch官网下载页面&#xff0c;下载Elasticsearch 在如下页面选择Elasticsearch版本&#xff0c;点击download按钮&#xff0c;进入下载页面 右键选择自己操作系统对应的版本&#xff0c;复制下载链接 然后通过wget命令下载Elastics…

Flink API 的层次结构

Apache Flink 提供了多层 API&#xff0c;每层 API 针对不同的抽象层次和用途&#xff0c;使得开发者可以根据具体需求选择合适的 API 层次。以下是 Flink API 的层次结构及其简要说明&#xff1a;

案例精选 | 河北省某检察院安全运营中异构日志数据融合的实践探索

河北省某检察院是当地重要的法律监督机构&#xff0c;肩负着维护法律尊严和社会公平正义的重要职责。该机构依法独立行使检察权&#xff0c;负责对犯罪行为提起公诉&#xff0c;并监督整个诉讼过程&#xff0c;同时积极参与社会治理&#xff0c;保护公民权益&#xff0c;推动法…

SpringCloud框架学习(第二部分:Consul、LoadBalancer和openFeign)

目录 六、Consul服务注册和发现 1.基本介绍 2.下载运行 3.服务注册与发现 &#xff08;1&#xff09;支付服务provider8001注册进consul &#xff08;2&#xff09;修改订单服务cloud-consumer-order80 4.CAP &#xff08;1&#xff09;CAP理论 &#xff08;2&#x…

成都睿明智科技有限公司解锁抖音电商新玩法

在这个短视频风起云涌的时代&#xff0c;抖音电商以其独特的魅力迅速崛起&#xff0c;成为众多商家争夺的流量高地。而在这片充满机遇与挑战的蓝海中&#xff0c;成都睿明智科技有限公司犹如一颗璀璨的新星&#xff0c;以其专业的抖音电商服务&#xff0c;助力无数品牌实现从零…

14.UE5爆炸伤害,场景变暗,时间轴

2-16 爆炸伤害&#xff0c;球体监测&#xff0c;场景变暗、时间轴_哔哩哔哩_bilibili 目录 1.UE5的爆炸伤害 ​2.后期盒子实现场景变暗 1.UE5的爆炸伤害 进入流星火雨的发射物蓝图编辑器中 对我们以前的重叠事件进行回顾&#xff0c;并修改使之实现爆炸伤害的效果 这是我们…

LeetCode面试经典150题C++实现,更新中

用C实现下面网址的题目 https://leetcode.cn/problems/merge-sorted-array/?envTypestudy-plan-v2&envIdtop-interview-150 1、数组\字符串 88合并两个有序数组 以下是使用 C 实现合并两个有序数组的代码及测试用例 C代码实现 #include <iostream> #include &l…

YOLO即插即用---PConv

Run, Don’t Walk: Chasing Higher FLOPS for Faster Neural Networks 论文地址&#xff1a; 1. 论文解决的问题 2. 解决问题的方法 3. PConv 的适用范围 4. PConv 在目标检测中的应用 5. 评估方法 6. 潜在挑战 7. 未来研究方向 8.即插即用代码 论文地址&#xff1a; …

手写jdbc 工具类(封装思维,解决硬编码...)

目录 前言 手写jdbc 工具类 封装思维 对于封装思维的理解 举一个关于封装思维的例子 解决硬编码 什么是硬编码&#xff1f; 硬编码的例子&#xff1a; 解决办法 解法1 解法2 解法3 jdbc工具类总的代码如下 资源关闭的先后问题 解决办法&#xff1a; 总结 …

数据库的四个基本概念

数据&#xff0c;数据库&#xff0c;数据库管理系统和数据库系统是与数据库技术密切相关的4个基本概念。 1. 数据&#xff08;data&#xff09; 描述事物的符号记录&#xff0c;譬如&#xff1a;数字、文字、图形、图像、音频、视频等&#xff0c;多种表现形式&#xff0c;均可…

java---认识异常(详解)

还有大家来到权权的博客~欢迎大家对我的博客提出意见哦&#xff0c;有错误会及时改进的~点击进入我的博客主页 目录 一、异常的概念及体系结构1.1 异常的概念1.2 异常的体系结构1.3异常的分类 二、异常的处理2.1防御式编程2.2 异常的抛出2.3 异常的捕获2.3.1异常声明throws2.3.…

移远通信亮相骁龙AI PC生态科技日,以领先的5G及Wi-Fi产品革新PC用户体验

PC作为人们学习、办公、娱乐的重要工具&#xff0c;已经深度融入我们的工作和生活。随着物联网技术的快速发展&#xff0c;以及人们对PC性能要求的逐步提高&#xff0c;AI PC成为了行业发展的重要趋势。 11月7-8日&#xff0c;骁龙AI PC生态科技日在深圳举办。作为高通骁龙的重…

【云原生开发】namespace管理的后端开发设计与实现

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

老破机器硬盘要坏,转移虚拟机里的打字平台过程全记录

我有一台老破机器&#xff0c;说破其实没多破&#xff0c;但是老应该是有几年了&#xff0c;这机器一开始一直放在领导办公室不让人用&#xff0c;后来因为单位整体搬迁&#xff0c;我跟领导讨了来&#xff0c;win10的系统&#xff0c;我装了个虚拟机好像是15的版本&#xff0c…

【JavaEE初阶】多线程上部

文章目录 本篇目标&#xff1a;一、认识线程&#xff08;Thread&#xff09;1.概念&#xff1a;2.创建线程 二、Thread 类及常见方法2.1 Thread 的常见构造方法2.2 Thread 的几个常见属性2.3 启动⼀个线程 - start()2.4 中断⼀个线程2.5 等待⼀个线程 - join()2.6 获取当前线程…