@ConfigurationProperties 注解原理

news2024/11/13 16:52:29

前言

@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 {

    @Resource
    private PropertyResolver env;
    
    @Test
    public void var1Test() {
        String var1 = env.getProperty("env101.var1");
        log.info("Environment 配置获取 {}", var1);
    }
}

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

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

相关文章

(2022,域邻近度)通过自适应感知核调制的 few-shot 图像生成

Few-shot Image Generation via Adaptation-Aware Kernel Modulation 公众号&#xff1a;EDPJ 目录 0. 摘要 1. 简介 2. 相关工作 3. 通过源-目标域接近度的视角重新审视 FSIG 3.1 源-目标域邻近度分析 3.2 临近假设松弛下的 FSIG 方法 4. 自适应感知核调制 5. 实证研…

js实现日历效果

使用js实现日历效果&#xff0c;主要用到了元素的创建以及添加 对应的方法是document.createElement()和document.appendChild() 主要实现思路&#xff1a; 用div布局把日历的页面框架搭建出来依次遍历上月&#xff0c;本月&#xff0c;下月的天数切换月份的时候首先清空所有日…

在服务器安装mysql步骤以及mysql数据库连接报错:is not allowed to connect to this mysql server

mysql xxx is not allowed to connect to this MySQL server 服务器上面安装的mysql数据库在本地连接的时候报错&#xff1a;is not allowed to connect to this MySQL server 出现这种情况的原因是因为&#xff1a; mysql数据库只允许自身所在的本机器连接&#xff0c;不允许…

排序算法——直接选择排序

直接选择排序 以升序排序为例 文章目录 直接选择排序算法步骤动图演示实现代码改进算法&#xff08;双指针&#xff09;具体步骤处理特殊情况&#xff1a;实现代码 时间复杂度 算法步骤 方法一&#xff1a;直接交换数组元素 将第一个元素与其他元素进行比较&#xff0c;若其…

初识网络之再看tcp协议

目录 一、tcp协议段格式 二、tcp协议的解包 三、tcp协议的分用 四、TCP可靠性问题 1. 不可靠存在原因 2. 常见的不可靠问题 3. 如何保证可靠性 4. 确认应答机制 5. 序号 五、tcp报头其余字段 1. 16位窗口大小 2. tcp的6个标记位 2.1 SYN 2.2 FIN 2.3 ACK 2.4 P…

【Linux】C语言中多线程的创建、退出、回收、分离

概述 线程是轻量级的进程&#xff08;LWP&#xff1a;light weight process&#xff09;&#xff0c;在 Linux 环境下线程的本质仍是进程。在计算机上运行的程序是一组指令及指令参数的组合&#xff0c;指令按照既定的逻辑控制计算机运行。操作系统会以进程为单位&#xff0c;…

【Spring AOP】面向切面编程

&#x1f389;&#x1f389;&#x1f389;点进来你就是我的人了博主主页&#xff1a;&#x1f648;&#x1f648;&#x1f648;戳一戳,欢迎大佬指点! 欢迎志同道合的朋友一起加油喔&#x1f93a;&#x1f93a;&#x1f93a; 目录 1. 什么是Spring AOP&#xff1f; 2. 为什么要…

NFC type 12345 tag介绍

NFC(近场通信)被称为短距离无线技术&#xff0c;是一套通信协议&#xff0c;NFC技术将非接读卡器/Reader、非接标签/Tag和点对点(Peer-to-Peer)数据交换的功能设计融为一体!使电子设备之间能够进行简单、安全的双向交互。为推动NFC技术发展&#xff0c;2004年&#xff0c;诺基亚…

Stable-Diffusion环境搭建

硬件可以采用DELL R7525 搭配L4 或者T4 等等企业级显卡 环境如下&#xff1a; 可以看到有相应的GPU卡信息 esxi 7.u3 信息 设置GPU穿透方式 查看相应的虚拟机参数信息 PCI 设备加载穿透GPU信息 启动uefi 设置相应的参数信息 https://docs.nvidia.com/grid/latest/grid-vgpu-re…

如何检测视频中的绿屏、绿帧问题

今天给项目拷机&#xff0c;发现视频会偶现绿屏&#xff0c;非常偶现&#xff0c;很难复现出来。 由于问题暂时没有定位&#xff0c;只能先表面解决一下&#xff0c;就是过滤掉出现绿屏的帧。 当然&#xff0c;首先要把绿帧检测出来&#xff0c;才能做后续的补救措施。 绿屏、…

电感公式推导

目录 电感的磁感应强度用&#xff1a;B表示 加入磁芯的可以提高磁感应强度&#xff1a;BμNI &#xff08;μ > μ0&#xff09; 磁芯的磁通量用&#xff1a;Φ来表示 一匝线圈感生电动势用&#xff1a;E来表示 在整个电感线圈的里面产生的感生电动势用UL来表示&#xff…

软件测试项目实战,电商项目核心业务测试分析(全覆盖)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 登陆功能怎么测试…

第16章_多版本并发控制

第16章_多版本并发控制 1. 什么是MVCC MVCC(Multiversion Concurrency Control)&#xff0c;多版本并发控制。顾名思义&#xff0c;MVCC是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换言之&#xff0…

chapter9: SpringBoot自定义Starter

尚硅谷SpringBoot顶尖教程 1. 自定义starter介绍 自定义starter从下面两个方面着手&#xff1a; 这个自定义starter的场景需要用到哪些依赖&#xff1f;如何编写自定义starter的自动配置&#xff1f; 查看springboot提供的已有starter组件的自动配置类&#xff0c;基本使用…

NFC Forum Type2 Tag

RC522作为一款NFC读写芯片&#xff0c;性价比还是很高的&#xff0c;因为在项目里需要采用NFC OOB配对&#xff0c;所以需要读取配对方模拟的NFC卡片信息 读取对象采用NRF52832&#xff0c;使用其NFC功能模拟type2 tag&#xff0c;但是读取方式和M1卡不一样&#xff0c;踩了不…

软件测试员不要过于迷信技术,忽视软技能

精于技术对于测试员&#xff0c;乃至技术员本身没毛病&#xff0c;甚至应大加赞赏&#xff0c;在组织中更应像国宝熊猫一样照顾好。然而我们发现&#xff0c;一些精于技术的测试员混的并不好。“纯正”的技术人员就该吃亏&#xff1f;问题到底出现在哪里&#xff1f; 根据我对…

南大通用GBase 8c 多模多态分布式数据库系列二之安装与卸载

目录 一.前言 二. 学习目标 三. 安装流程 四. 配置要求 1. 硬件配置要求 2. 软件配置要求 3. 软件依赖配置 五. 集群规划 1. 物理规划 2. 演示环境配置 六. 安装前环境检查 1. 关闭防火墙 2. 关闭SELINUX 3. 主机名检查、依赖检查 4. Gbase用户配置sudo 七. 配…

科研闭环指南|关于 Review Rebuttal 的二三事

两个月前投稿的论文审稿&#xff08;Review&#xff09;意见快下来了&#xff0c;期间我也是作为审稿人&#xff08;Reviewer&#xff09;完成了4篇工作的审稿工作。回想自己从入学以来也算是审过 10 篇左右的稿子了&#xff0c;也参与过 Review 之后的 Rebuttal 环节。下面我就…

思维决定发展,软件测试人也不例外

最近特别懒&#xff0c;不想码字&#xff0c;原本写作就很差&#xff0c;更是退化严重。社招和校招面试过很多人&#xff0c;从十年前自己还很弱的时候学着面试&#xff0c;到数百次面试积累之后&#xff0c;面对候选人的时候&#xff0c;我的内心依然有些许紧张&#xff0c;非…

《Reinforcement Learning: An Introduction》第5章笔记

Chapter 5 Monte Carlo Methods Monte Carlo 方法不假设拥有完备的环境知识&#xff0c;它仅仅需要经验–从与环境的实际或模拟交互中得到的一系列的状态、动作、和奖励的样本序列。 Monte Carlo方法是基于平均采样回报的来解决强化学习问题的方法。 5.1 Monte Carlo Predic…