@ConfigurationProperties 注解原理

news/2025/2/18 10:10:30/

前言

@ConfigurationProperties注解是 SpringBoot 提供的一种更加便捷来处理配置文件中的属性值的方式,可以通过自动绑定和类型转换等机制,将指定前缀的属性集合自动绑定到一个Bean对象上。

加载原理

在 Springboot 启动流程加载配置的 prepareEnvironment() 方法中,有一个重要的步骤方法 bindToSpringApplication(environment),它的作用是将配置文件中的属性值绑定到被 @ConfigurationProperties 注解标记的 Bean对象中。但此时这些对象还没有被 Spring 容器管理,因此无法完成属性的自动注入。那么这些Bean对象又是什么时候被注册到 Spring 容器中的呢?

这就涉及到了 ConfigurationPropertiesBindingPostProcessor 类,它是 Bean后置处理器,负责扫描容器中所有被 @ConfigurationProperties 注解所标记的 Bean对象。如果找到了,则会使用 Binder 组件将外部属性的值绑定到它们身上,从而实现自动注入。

  • bindToSpringApplication 主要是将属性值绑定到 Bean 对象中;
  • ConfigurationPropertiesBindingPostProcessor 负责在 Spring 容器启动时将被注解标记的 Bean 对象注册到容器中,并完成后续的属性注入操作;

从springboot程序启动看配置初始化

Springboot 程序启动加载流程里,会执行SpringApplication.run中的prepareEnvironment()方法进行配置的初始化,那初始化过程每一步都做了什么呢?

private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners,DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {/** * 1、创建 ConfigurableEnvironment 对象:首先调用 getOrCreateEnvironment() 方法获取或创建* ConfigurableEnvironment 对象,该对象用于存储环境参数。如果已经存在 ConfigurableEnvironment 对象,则直接使用它;否则,根据用户的配置和默认配置创建一个新的。*/ConfigurableEnvironment environment = getOrCreateEnvironment();/*** 2、解析并加载用户指定的配置文件,将其作为 PropertySource 添加到环境对象中。该方法默认会解析 application.properties 和 application.yml 文件,并将其添加到 ConfigurableEnvironment 对象中。* PropertySource 或 PropertySourcesPlaceholderConfigurer 加载应用程序的定制化配置。*/configureEnvironment(environment, applicationArguments.getSourceArgs());// 3、加载所有的系统属性,并将它们添加到 ConfigurableEnvironment 对象中ConfigurationPropertySources.attach(environment);// 4、通知监听器环境参数已经准备就绪listeners.environmentPrepared(bootstrapContext, environment);/***  5、将默认的属性源中的所有属性值移到环境对象的队列末尾,这样用户自定义的属性值就可以覆盖默认的属性值。这是为了避免用户无意中覆盖了 Spring Boot 所提供的默认属性。*/DefaultPropertiesPropertySource.moveToEnd(environment);Assert.state(!environment.containsProperty("spring.main.environment-prefix"),"Environment prefix cannot be set via properties.");// 6、将 Spring Boot 应用程序的属性绑定到环境对象上,以便能够正确地读取和使用这些配置属性bindToSpringApplication(environment);// 7、如果没有自定义的环境类型,则使用 EnvironmentConverter 类型将环境对象转换为标准的环境类型,并添加到 ConfigurableEnvironment 对象中。if (!this.isCustomEnvironment) {EnvironmentConverter environmentConverter = new EnvironmentConverter(getClassLoader());environment = environmentConverter.convertEnvironmentIfNecessary(environment, deduceEnvironmentClass());}// 8、再次加载系统配置,以防止被其他配置覆盖ConfigurationPropertySources.attach(environment);return environment;
}

看看它的配置加载流程步骤:

  • 创建 环境对象 ConfigurableEnvironment 用于存储环境参数;
  • configureEnvironment 方法加载默认的 application.properties 和 application.yml 配置文件;以及用户指定的配置文件,将其封装为 PropertySource 添加到环境对象中;
  • attach(): 加载所有的系统属性,并将它们添加到环境对象中;
  • listeners.environmentPrepared(): 发送环境参数配置已经准备就绪的监听通知;
  • moveToEnd(): 将 系统默认 的属性源中的所有属性值移到环境对象的队列末尾,这样用户自定义的属性值就可以覆盖默认的属性值。
  • bindToSpringApplication: 应用程序的属性绑定到 Bean 对象上;
  • attach(): 再次加载系统配置,以防止被其他配置覆盖;

上边的配置加载流程中,各种配置属性会封装成一个个抽象的数据结构 PropertySource中,这个数据结构代码格式如下,key-value形式。

public abstract class PropertySource<T> {protected final String name; // 属性源名称protected final T source; // 属性源值(一个泛型,比如Map,Property)public String getName();  // 获取属性源的名字  public T getSource(); // 获取属性源值  public boolean containsProperty(String name);  //是否包含某个属性  public abstract Object getProperty(String name);   //得到属性名对应的属性值   
} 

PropertySource 有诸多的实现类用于管理应用程序的配置属性。不同的 PropertySource 实现类可以从不同的来源获取配置属性,例如文件、环境变量、命令行参数等。其中涉及到的一些实现类有:

关系图

  • MapPropertySource: Map 键值对的对象转换为 PropertySource 对象的适配器;
  • PropertiesPropertySource: Properties 对象中的所有配置属性转换为 Spring 环境中的属性值;
  • ResourcePropertySource: 从文件系统或者 classpath 中加载配置属性,封装成 PropertySource对象;
  • ServletConfigPropertySource: Servlet 配置中读取配置属性,封装成 PropertySource 对象;
  • ServletContextPropertySource: Servlet 上下文中读取配置属性,封装成 PropertySource 对象;
  • StubPropertySource: 是个空的实现类,它的作用仅仅是给 CompositePropertySource 类作为默认的父级属性源,以避免空指针异常;
  • CompositePropertySource: 是个复合型的实现类,内部维护了 PropertySource集合队列,可以将多个 PropertySource 对象合并;
  • SystemEnvironmentPropertySource: 操作系统环境变量中读取配置属性,封装成 PropertySource 对象;

上边各类配置初始化生成的 PropertySource 对象会被维护到集合队列中。

List<PropertySource<?>> sources = new ArrayList<PropertySource<?>>()

配置初始化完毕,应用程序上下文AbstractApplicationContext会加载配置,这样程序在运行时就可以随时获取配置信息了。

 private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,ApplicationArguments applicationArguments, Banner printedBanner) {// 应用上下文加载环境对象context.setEnvironment(environment);postProcessApplicationContext(context);.........}

3、读取配置

看明白上边配置加载的流程,其实读取配置就容易理解了,无非就是遍历队列里的PropertySource,拿属性名称name匹配对应的属性值sourcePropertyResolver是获取配置的关键类,其内部提供了操作PropertySource 队列的方法,核心方法getProperty(key)获取配置值,看了下这个类的依赖关系,发现 Environment 是它子类。

那么直接用 PropertyResolver 来获取配置属性其实也是可以的,到这我们就大致明白了 Springboot 配置的加载和读取了。

@Slf4j
@SpringBootTest
public class EnvironmentTest {@Resourceprivate PropertyResolver env;@Testpublic void var1Test() {String var1 = env.getProperty("env101.var1");log.info("Environment 配置获取 {}", var1);}
}

http://www.ppmy.cn/news/451601.html

相关文章

PyTorch 深度学习 || 2. 全连接网络 | Ch2.3 PyTorch 全连接自编码网络的无监督学习

PyTorch 全连接自编码网络的无监督学习 文章目录 PyTorch 全连接自编码网络的无监督学习1. 数据去噪1.1 计算库和数据准备工作1.2 构建自编码网络1.3 调用主函数1.4 可视化 2. 数据的重建与降维2.1 计算模块和数据的准备2.2 自编码网络数据准备2.3 自编码网络的构建2.4 自编码网…

Android 使用adb修改手机分辨率、dpi

为了适配不同尺寸屏幕的手机&#xff0c;最简单的方式就是通过adb修改分辨率和dpi adb安装 Android Studio 安装adb&#xff08;Android Debug Bridge&#xff09; adb官网下载 https://developer.android.com/studio/releases/platform-tools?hlzh-cn adb修改size 查看…

ufs2.0测试软件,三星S8被爆混用UFS闪存 如何测试是UFS 2.0还是UFS 2.1?

华为 “闪存门”事件从 4 月份开始至今并未平息&#xff0c;主要还是因为消费者对华为的官方说法并不满意&#xff0c;因为华为一直强调自己不背锅&#xff0c;毕竟是供应链 UFS 闪存缺货造成的影响。关键是华为还认为 eMMc 与 UFS 不同闪存不会影响系统体验一致性。不得不说&a…

三星手机动态修改分辨率信息

较早前文章介绍了如何在安卓手机上安装激活XPOSED框架&#xff0c;XPOSED框架的极强的功能各位都清楚&#xff0c;能够不修改应用程序的前提下&#xff0c;修改系统内核的参数&#xff0c;好比在某些应用领域&#xff0c;各位需要修改手机的某个系统参数&#xff0c;这时就需要…

卡位高端:三星S8卖断货折射市场节点

5月18日晚上&#xff0c;三星在古北水镇长城剧场发布新旗舰机型Galaxy S8|S8的时候&#xff0c;高东真并没有想到这款手机的上市流程&#xff0c;会在半月之后进行“延长预约日期并增加购机优惠”方面的调整。 尤其是这种轻易调整即可导致营销成本剧升、供货量面临巨大考验的策…

高通骁龙845的android手机有哪些,2018年骁龙845手机有哪些?骁龙845手机怎么样?...

2018骁龙845手机有哪些&#xff1f;骁龙845手机怎么样&#xff1f;在今年12月末高通正式确定了骁龙845处理器的成功研发&#xff0c;对于手机控来说&#xff0c;这款骁龙845处理器会应用在哪些手机上无疑是非常令人期待和关注的&#xff0c;这里提供部分可能信息&#xff0c;希…

屏幕小于6英寸的手机_6英寸屏幕真的大么?你可能对“全面屏”有什么误解!详解全面屏手机那些事...

6英寸屏幕真的大么&#xff1f;你可能对“全面屏”有什么误解&#xff01;详解全面屏手机那些事 2018-05-15 10:31:35 225点赞 278收藏 118评论 小编注&#xff1a;想获得更多专属福利吗&#xff1f;金币加成、尊享众测、专属勋章、达人福利任务你想要吗&#xff1f;如果想要&a…

4g运行内存手机还能用多久_看完就明白:目前手机运行内存超过4G就是浪费

腾讯数码讯(文心)据Android Central网站报道&#xff0c;vivo 乎要推出一款运行内存容量高达10GB的手机。这意味着这款手机运行内存容量堪比许多游戏PC&#xff0c;比大多数手机多约6GB。这让许多手机用户都感到迷惑不解&#xff0c;心里直嘀咕&#xff1a;手机真的需要10GB运行…