Spring 配置绑定原理分析

Spring 配置绑定原理分析

前言

Spring 应用中存在诸多配置,有的是系统配置,有的命令行启动参数配置,有的是yaml配置,有的是分布式配置中心配置,但对使用者而言总是可以通过@ConfigurationProperties将它关联到一个JavaBean当中或者使用@Value绑定,使得获取这这些来自不同地方的配置就像获取一个对象属性那么简单,那么它是如何来完成这个工作的呢?

结构层次

AbstractEnvironment是Spring环境的抽象实体,它存在一个MutablePropertySources类型(意为可变的配置源)的变量 propertySources,后者维护了系统中所有的配置源,系统环境变量可以是一个配置源,启动参数可以是一个配置源,application.yaml可以是一个配置源,甚至我们可以自定义一个配置源

image-20241106210028035

数据源之间的冲突

我们定义了这么一个配置,我们指定了hk.name的默认值

@Data
@Configuration
@ConfigurationProperties("hk")
public class HkConfig {
    private String name  = "default";
}

我们在application.yaml做出如下配置

hk:
  name: huakai

然后在启动参数也做出配置

--hk.name=hualuo

那么最终我们获取到的hk.name应该是哪一个呢?

答案是这是一个约定,原则是通常遵循着"靠近应用优先原则",通常情况下,

优先级顺序一般如下(从高到低):

  1. 命令行参数
  2. application.propertiesapplication.yml
  3. 操作系统环境变量
  4. JNDI 属性
  5. JVM 系统属性
  6. @PropertySource 注解配置的属性文件
  7. 默认值(在代码中指定的默认值)

实现上是如何做的呢

我们可以看到MutablePropertySources自身维护着一个List<PropertySource<?>>而配置的优先级别决定于配置源在list中的位置,配置源所处的位置越靠前那么它的优先级越高,后者又是因为Spring的策略是遍历配置源如果找到立即返回,这在Binder的实现中可见一斑

private ConfigurationProperty findProperty(ConfigurationPropertyName name, Context context) {
    if (name.isEmpty()) {
       return null;
    }
    for (ConfigurationPropertySource source : context.getSources()) {
       ConfigurationProperty property = source.getConfigurationProperty(name);
       if (property != null) {
          return property;
       }
    }
    return null;
}

MutablePropertySources

这个可变的数据源,提供了一些添加数据源的方法,包括以下两个

addFirst()

​ 这意味着被添加的数据源将最高的优先级

addLast()

​ 这意味着被添加的数据源将最低的优先级

	public void addFirst(PropertySource<?> propertySource) {
		synchronized (this.propertySourceList) {
			removeIfPresent(propertySource);
			this.propertySourceList.add(0, propertySource);
		}
	}

	public void addLast(PropertySource<?> propertySource) {
		synchronized (this.propertySourceList) {
			removeIfPresent(propertySource);
			this.propertySourceList.add(propertySource);
		}
	}

自定义PropertySources

我们定义一个指定的数据源并且期望它的优先级最高

CustomPropertySource

package com.huakai.springenv.config;

import org.springframework.core.env.PropertySource;
import java.util.HashMap;
import java.util.Map;

public class CustomPropertySource extends PropertySource<Object> {

    private final Map<String, String> properties = new HashMap<>();

    public CustomPropertySource(String name) {
        super(name);
        // 在此添加您自定义的属性
        properties.put("hk.name", "customValue");
    }

    @Override
    public Object getProperty(String name) {
        return properties.get(name);
    }
}

CustomPropertySourcePostProcessor

package com.huakai.springenv.config;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.env.EnvironmentPostProcessor;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MutablePropertySources;

public class CustomPropertySourcePostProcessor implements EnvironmentPostProcessor {



    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        MutablePropertySources propertySources = environment.getPropertySources();
        CustomPropertySource customPropertySource = new CustomPropertySource("customPropertySource");
        propertySources.addFirst(customPropertySource);
    }
}

spring.factories

org.springframework.boot.env.EnvironmentPostProcessor=com.huakai.springenv.config.CustomPropertySourcePostProcessor

ps:EnvironmentPostProcessor 在 Spring 应用上下文初始化之前就被加载和执行所以只能通过该方式配置

测试

@Resource
private HkConfig hkConfig;

@RequestMapping("testGetConfig")
public String test2() {
    return hkConfig.getName();
}

image-20241106214520252

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

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

相关文章

爬虫下载网页文夹

爬虫下载网页pdf文件 import os import requests from bs4 import BeautifulSoup from urllib.parse import urljoin from urllib.parse import urljoin, unquote from tqdm import tqdm # 设置网页的URL base_url "http://119/download/dzz/pdf/"# 创建保存文件的…

数据结构-归并排序笔记

【数据结构】八大排序(超详解附动图源码)_数据结构排序-CSDN博客 看这个学思路 一 归并排序介绍: 归并排序(MERGE-SORT)是利用归并的思想实现的排序方法&#xff0c;该算法采用经典的分治(divide-and-conquer)策略(分治法将问题分(divide)成一些小的问题然后递归求解&#xf…

编译器优化乌龙——记一次死循环不进入问题

记一次死循环不生效问题 看如下代码&#xff0c;本意是我们模拟一次死循环&#xff0c;然后会在中断处理函数中更改waiting的值&#xff0c;更改waiting的值后&#xff0c;跳出死循环。 int waiting 0; while(waiting0){}运行起来发现&#xff0c;程序根本就没有进入这个死循…

构建第一个ArkTs应用

1、新建第一个页面文件。在“Project”窗口&#xff0c;点击“entry > src > main > ets > pages”&#xff0c;打开“Index.ets”文件&#xff0c;进行页面的编写。 2、新建第二个页面文件。在“Project”窗口&#xff0c;打开“entry > src > main > e…

一文搞懂Linux kernel编译步骤

一、前言 什么是Linux的内核编译呢&#xff1f;简单来说&#xff0c;Linux内核编译是一个将内核源代码转换成可在特定的硬件架构上运行的二进制文件的过程。通过编译内核&#xff0c;我们可以根据自己的需求和兴趣对内核进行定制和优化&#xff0c;以满足特定的应用场景。下文…

IDEA构建JavaWeb项目,并通过Tomcat成功运行

目录 一、Tomcat简介 二、Tomcat安装步骤 1.选择分支下载 2.点击下载zip安装包 3.解压到没有中文、空格和特殊字符的目录下 4.双击bin目录下的startup.bat脚本启动Tomcat 5.浏览器访问Tomcat 6.关闭Tomcat服务器 三、Tomcat目录介绍 四、WEB项目的标准结构 五、WEB…

消息通知——公众号、小程序、短信对比

消息通知——公众号、小程序、短信对比 引言 在数字化时代&#xff0c;高效、准确的消息通知对于提升用户体验、增强用户粘性至关重要。本报告将深入分析三种常见的消息通知方式&#xff1a;微信公众号推送、微信小程序推送以及手机短信推送&#xff0c;从实现方式、优缺点及细…

三维测量与建模笔记 - 3.2 直接线性变换法标定DLT

DLT - Direct Linear Transform 上图中&#xff0c;透视成像对应的公式是共线方程&#xff0c;可以参考以下链接&#xff1a; https://zhuanlan.zhihu.com/p/101549821https://zhuanlan.zhihu.com/p/101549821 对于标定来说&#xff0c;需要找到。已知量是。 (u,v)是…

消息队列面试——打破沙锅问到底

消息队列的面试连环炮 前言 你用过消息队列么&#xff1f;说说你们项目里是怎么用消息队列的&#xff1f; 我们有一个订单系统&#xff0c;订单系统会每次下一个新订单的时候&#xff0c;就会发送一条消息到ActiveMQ里面去&#xff0c;后台有一个库存系统&#xff0c;负责获取…

【论文复现】KAN卷积:医学图像分割新前沿

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀知识图谱推理 1. 概述2. 核心创新点3. 模块介绍KANUNext模块 4. 本文主要结构5. 主要代码6. 数据集7. 结果展示8. 参考文献 前言&#xff1a;…

Oracle与SQL Server的语法区别

1&#xff09;日期和日期转换函数。 SQL: SELECT A.*, CASE WHEN NVL(PAA009,) OR PAA009 >Convert(Varchar(10), SYSDATE,120) THEN Y ELSE N END AS ActiveUser FROM POWPAA A WHERE PAA001admin or PAA002admin Oracle: SELECT A.*, CASE WHEN NVL(PAA009,) or PAA009&…

基于TRIZ理论的便携式光伏手机充电装置创新

随着智能手机功能的日益强大&#xff0c;电量消耗问题也日益凸显&#xff0c;尤其是在户外活动时&#xff0c;电量告急常常让人措手不及。面对这一挑战&#xff0c;基于TRIZ&#xff08;发明问题解决理论&#xff09;的创新思维&#xff0c;一款全新的便携式光伏手机充电装置应…

Vue3父传子

1. App.vue - 父组件 咱们先来看左边的 App.vue&#xff0c;它扮演的是“父亲”角色——你可以想象它是一位热心的老爸&#xff0c;手里拿着一条消息&#xff0c;正准备把这条消息送到“儿子”那里。 <script setup> // 这个 setup 就像一个神奇的开关&#xff0c;一开…

前端 算法 双指针

文章目录 三数之和移动零盛最多水的容器接雨水 三数之和 leetcode 三数之和 题目链接 给你一个整数数组 nums &#xff0c;判断是否存在三元组 [nums[i], nums[j], nums[k]] 满足 i ! j、i ! k 且 j ! k &#xff0c;同时还满足 nums[i] nums[j] nums[k] 0 。请你返回所有…

EPSON机械手与第三方相机的校准功能设计By python

EPSON机械手与第三方相机的校准功能设计By python 使用Python来实现EPSON机械手与第三方相机的校准功能是一个复杂但可行的任务。这通常涉及以下几个步骤:硬件接口通信、图像处理、标定算法实现和控制逻辑编写。 1. 环境准备 首先,库 pip install numpy opencv-python pyse…

NPU 可不可以代替 GPU

结论 先说结论&#xff0c;GPU分为可以做图形处理的传统意义上的真GPU&#xff0c;做HPC计算的GPGPU和做AI加速计算的GPGPU&#xff0c;所以下面分别说&#xff1a; 对于做图形处理的GPU&#xff0c;这个就和NPU 一样&#xff0c;属于DSA&#xff0c;没有替代性。当然&#xf…

python画图|hist()函数画直方图进阶

【1】引言 前序已经学习了hist()函数画直方图的基础教程&#xff0c;相关文章见下述链接&#xff1a; python画图|hist()函数画直方图初探-CSDN博客 在这里我们初步认识了hist()函数&#xff0c;并使用该函数画出了8个直方图。 之后又用bar(&#xff09;函数进行对比&#…

推荐一款非常好用的C/C++在线编译器

C/C作为一门底层、高效的编程语言&#xff0c;广泛应用于系统开发、游戏引擎、嵌入式系统等领域。然而&#xff0c;C/C的开发环境配置会让开发者把部分时间消耗在这件事上&#xff0c;也经常会遇到各种各样的环境问题。 本地开发的痛点 环境配置复杂&#xff1a;C/C的开发环境…

kafka如何获取 topic 主题的列表?

大家好&#xff0c;我是锋哥。今天分享关于【kafka如何获取 topic 主题的列表&#xff1f;】面试题&#xff1f;希望对大家有帮助&#xff1b; kafka如何获取 topic 主题的列表&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在Kafka中&#xff0c;可以…

用示例来看C2Rust工具的使用和功能介绍

C2Rust可以将C语言的源代码转换成Rust语言的源代码。下面是一个简单的C语言代码示例&#xff0c;以及使用c2Rust工具将其转换为Rust安全代码的过程。 C语言源代码示例 // example.c #include <stdio.h>int add(int a, int b) {return a b; }int main() {int result a…