您当前的位置:首页 > 电脑百科 > 程序开发 > 框架

你绝对不知道的 SpringBoot 的外部化配置特性!

时间:2023-03-20 17:13:22  来源:微信公众号  作者:Java极客技术
今天了不起带大家研究了一个 SpringBoot​ 的外部化配置,并且通过实际的一个 case 跟踪代码的调用链来给大家测试了一下,虽然说这个知识点我们经常都在使用,但是没看到底层源码的时候我们并不知道这样的一个功能底层是怎样的复杂的。

作为 JAVA​ 程序员,相信大家都知道,我们日常的 SpringBoot​ 项目会有一个配置文件 Application.properties 文件。

里面会配置很多参数,例如服务的端口等,这些都只是默认值,在不改变配置文件里面内容的情况下,我们可以通过在部署的时候,传递一个相应的参数来替换默认的参数。

那么问题来了,你有想过为什么可以这样吗?为什么 SpringBoot 部署时传递的启动配置会生效,而配置文件中的配置就不生效了呢?或者说这两者的优先级是什么样子的呢?

外部化配置

要解释上面的问题,我们就需要知道 SpringBoot 到底支持哪些配置形式,以及这些配置方式的优先级是什么样子的,只有搞清楚了这个,才能真正的解决配置的优先级问题。

在 SpringBoot 的官方文档中我们可以看到这么一段描述

图片

用了不起我拙劣的英语翻译一下,大概的意思就是:Spring Boot​ 提供了将配置文件外部化的功能,这样您就可以在不同环境下使用相同的应用程序代码。您可以使用 properties​ 文件、YAML 文件、环境变量以及命令行参数来外部化配置文件。

通过 @Value​ 注解,属性值可以直接注入到 beans​ 中,通过 Environment abstraction​(环境映射)可以访问其他位置,或者使用 @ConfigurationProperties 绑定结构化对象。

有哪些外部配置

既然上面提到了 SpringBoot​ 提供了外部化配置,那么 SpringBoot 提供了哪些配置呢?依然是通过官方文档,我们可以看到有如下配置列表

图片

从上图可以看到 SpringBoot 总共内置了 17 种外部化配置方法,而且这 17 种的优先级是从上到下依次优先的。这些方式中我们常用的有 4 命令行方法,9 Java 系统环境变量,10 操作系统环境变量,以及 12 到 15 到配置文件的形式。

通过上面的顺序我们就可以解释为什么我们通过命令行配置的参数会生效,而配置文件中的默认值就会忽略了,从而达到了覆盖配置的目的。

PropertySource

上面的文档中也提到了,SpringBoot​ 主要是通过 PropertySource​ 机制来实现多样属性源的,SpringBoot​ 的 PropertySource​ 是一种机制,用于加载和解析配置属性,可以从多种来源获取这些属性,例如文件、系统环境变量、JVM​ 系统属性和命令行参数等。PropertySource​ 是 Spring 框架中的一个抽象接口,它定义了如何读取属性源的方法。

图片

通过 SpringBoot​ 的代码,我们可以看到,org.springframework.core.env.PropertySource​ 是一个抽象类,实现在子类有很多,我们上面提到的命令行 PropertySource​ 是 org.springframework.core.env.CommandLinePropertySource。整体的类图如下,涵盖的内容还是很多的,感兴趣的小伙伴可以好好研究一番。

图片

另外在 SpringBoot​ 中,我们还可以使用 @PropertySource 注解来自定义指定要加载的属性文件。例如,可以在应用程序的主类上添加以下注解:

@SpringBootApplication
@PropertySource("classpath:customer.properties")
public class CustomerProperties {
   // ...
}

这将告诉 SpringBoot​ 在 classpath​ 下查找名为 customer.properties​ 的文件,并将其加载为属性源。然后,可以使用 @Value​注解将属性值注入到 bean 中,如下所示:

@Service
public class MyService {
   @Value("${my.property}")
   private String myProperty;
   // ...
}

这里的 ${my.property}​ 是从 customer.properties​ 文件中获取的属性值。如果找不到该属性,那么 SpringBoot 将使用默认值,这里因为是自定义的属性,是没有默认值的,就会报错,项目无法启动。

具体实现是,SpringBoot​ 在启动时会自动加载和解析所有的 PropertySource​,包括默认的 PropertySource​ 和自定义的PropertySource​。这些属性值被存储在 Spring​ 环境中,可以通过 Spring​ 的 Environment​ 对象访问。当属性被注入到 bean​ 中时, Spring​ 会查找 Environment 对象并尝试解析属性的值。

总之,SpringBoot​ 的 PropertySource​ 提供了一种简单的方法来加载和解析应用程序的配置属性,这些属性可以从多个来源获取。它通过将属性值存储在 Spring 环境中,使其易于在应用程序的不同部分中使用。

调试

为了验证上面说的命令行的参数配置要优先于配置文件,我们创建一个 SpringBoot 项目,并且在 application.properties​ 文件中配置一个参数 name=JavaGeekTech​,而在 IDEA 启动窗口中配置 name=JAVA_JIKEJUSHU,分别如下所示

图片

图片

在写一个简单的 HelloController​ 类,并且通过 @Value​ 注解注入 name​ 属性,接下来我们就需要调试看下,SpringBoot​是如何将 name​ 属性赋值的。通过验证 name​ 会被赋值成 JAVA_JIKEJISHU​ 而不是 JavaGeekTech。

package com.example.demo.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

  @Value("${name}")
  private String name;

  @GetMapping(value = "/hello")
  public String hello() {
    return helloService.sayHello(name);
  }

}

接着我们启动 debug​,因为我们是基于 SpringBoot​ 的,属性的赋值是在创建 bean​ 的时候,从 createBean​,到 doCreateBean​,再到 org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory#populateBean​,因为每个 bean​ 都会经过很多 PostProcessor​ 的处理,属性赋值的 PostProcessor​ 是 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor#postProcessProperties

图片

里面的 metadata.inject​ 会调用到 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#inject​,再到 org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.AutowiredFieldElement#resolveFieldValue,

org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency,

org.springframework.beans.factory.support.DefaultListableBeanFactory#doResolveDependency,

org.springframework.beans.factory.support.AbstractBeanFactory#resolveEmbeddedValue,

org.springframework.core.env.AbstractPropertyResolver#resolveRequiredPlaceholders,

org.springframework.core.env.PropertySourcesPropertyResolver#getPropertyAsRawString,

org.springframework.core.env.PropertySourcesPropertyResolver#getProperty(java.lang.String, java.lang.Class<T>, boolean)

整体调用链还是挺长的,不过只要跟着思路,在配合断点,还是可以看看看出来的。

图片

在 getProperty​ 方法中,我们可以看到如下的逻辑,根据 key​ 获取到的 value​ 值为JAVA_JIKEJISHU。

图片

继续跟踪 getProperty​ 方法,我们可以看到这个方法 org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertySource#findConfigurationProperty(org.springframework.boot.context.properties.source.ConfigurationPropertyName),

图片

其中的 getSource() 中就有我们配置的两个属性源的数据,如下所示

图片

根据代码逻辑,我们也可以看到,在迭代的时候,如果找到了一个就直接返回了,所以得到的结果是JAVA_JIKEJISHU。

总结

今天了不起带大家研究了一个 SpringBoot​ 的外部化配置,并且通过实际的一个 case 跟踪代码的调用链来给大家测试了一下,虽然说这个知识点我们经常都在使用,但是没看到底层源码的时候我们并不知道这样的一个功能底层是怎样的复杂的。

这里还是要敬佩一下 SpringBoot 的开发者,同时也建议大家,在日常的开发中我们需要多看看底层的源码,通过不断的看源码,我们能更好的理解特性的实现原理,从而加强我们自身的能力。



Tags:SpringBoot   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
公司用了六年的 SpringBoot 项目部署方案,稳得一批!
本篇和大家分享的是springboot打包并结合shell脚本命令部署,重点在分享一个shell程序启动工具,希望能便利工作。 profiles指定不同环境的配置 maven-assembly-plugin打发布压...【详细内容】
2024-01-10  Search: SpringBoot  点击:(163)  评论:(0)  加入收藏
SpringBoot 中的热部署和热加载
在Spring Boot开发调试中,如果我们每修改一行代码都需要重启调试,可能会比较耗时。Spring Boot团队针对这个问题提供了spring-boot-devtools(简称:Devtools)插件,试图提高开发和调...【详细内容】
2023-11-06  Search: SpringBoot  点击:(250)  评论:(0)  加入收藏
SpringBoot 调用外部接口的四种方式
1、简介在Spring-Boot项目开发中,当本模块的代码需要访问外面模块接口,或外部url链接的需求的时候, 需要使用网络连接调用,下面提供了四种方式(排除dubbo的方式)供大家选择。方式...【详细内容】
2023-11-06  Search: SpringBoot  点击:(315)  评论:(0)  加入收藏
Springboot 框架中事件监听和发布机制详细介绍
事件监听和发布是Spring Framework中的一种机制,用于实现松散耦合的组件之间的通信。下面是事件监听和发布的详细过程:事件发布的过程: 创建事件对象:首先,您需要创建一个事件类,...【详细内容】
2023-11-02  Search: SpringBoot  点击:(264)  评论:(0)  加入收藏
Springboot 中的 PropertySource 管理配置属性的机制
Spring Framework 中的 PropertySource 是一种用于管理配置属性的机制,它允许你将配置信息从各种来源(如属性文件、环境变量、数据库等)加载到应用程序中。在 Spring 中,Propert...【详细内容】
2023-10-29  Search: SpringBoot  点击:(228)  评论:(0)  加入收藏
如何将本地jar文件打包到 springboot 执行jar文件中
这一系列课程将包含Spring Boot 许多关键的技术和工具,包括 Mybatis-Plus、Redis、Mongodb、MinIO、Kafka、MySQL、消息队列(MQ)、OAuth2 等相关内容。如何将本地jar文件打包到...【详细内容】
2023-10-27  Search: SpringBoot  点击:(271)  评论:(0)  加入收藏
Java面试题之SpringBoot 框架
谈谈怎么理解 SpringBoot 框架 Spring Boot 是 Spring 开源组织下的子项目, 是 Spring 组件一站式解决方案, 主要是 简化了使用 Spring 的难度, 简省了繁重的配置, 提供了各种启...【详细内容】
2023-09-28  Search: SpringBoot  点击:(213)  评论:(0)  加入收藏
SpringBoot 并发编程学习历程
本教程大概目录: 模拟单线程情节 用Callable实现 并发编程 用DeferedResult实现异步处理###模拟单线程情节。/** * Created by Fant.J. */@RestController@Slf4jpublic class...【详细内容】
2023-09-27  Search: SpringBoot  点击:(207)  评论:(0)  加入收藏
Springboot — 用更优雅的方式发HTTP请求(RestTemplate详解)
RestTemplate是Spring提供的用于访问Rest服务的客户端,RestTemplate提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。我之前的HTTP开发是用apache的Htt...【详细内容】
2023-09-14  Search: SpringBoot  点击:(317)  评论:(0)  加入收藏
16个SpringBoot 扩展接口
1.背景Spring的核心思想就是容器,当容器refresh的时候,外部看上去风平浪静,其实内部则是一片惊涛骇浪,汪洋一片。Springboot更是封装了Spring,遵循约定大于配置,加上自动装配的机...【详细内容】
2023-08-28  Search: SpringBoot  点击:(134)  评论:(0)  加入收藏
▌简易百科推荐
Web Components实践:如何搭建一个框架无关的AI组件库
一、让人又爱又恨的Web ComponentsWeb Components是一种用于构建可重用的Web元素的技术。它允许开发者创建自定义的HTML元素,这些元素可以在不同的Web应用程序中重复使用,并且...【详细内容】
2024-04-03  京东云开发者    Tags:Web Components   点击:(8)  评论:(0)  加入收藏
Kubernetes 集群 CPU 使用率只有 13% :这下大家该知道如何省钱了
作者 | THE STACK译者 | 刘雅梦策划 | Tina根据 CAST AI 对 4000 个 Kubernetes 集群的分析,Kubernetes 集群通常只使用 13% 的 CPU 和平均 20% 的内存,这表明存在严重的过度...【详细内容】
2024-03-08  InfoQ    Tags:Kubernetes   点击:(12)  评论:(0)  加入收藏
Spring Security:保障应用安全的利器
SpringSecurity作为一个功能强大的安全框架,为Java应用程序提供了全面的安全保障,包括认证、授权、防护和集成等方面。本文将介绍SpringSecurity在这些方面的特性和优势,以及它...【详细内容】
2024-02-27  风舞凋零叶    Tags:Spring Security   点击:(54)  评论:(0)  加入收藏
五大跨平台桌面应用开发框架:Electron、Tauri、Flutter等
一、什么是跨平台桌面应用开发框架跨平台桌面应用开发框架是一种工具或框架,它允许开发者使用一种统一的代码库或语言来创建能够在多个操作系统上运行的桌面应用程序。传统上...【详细内容】
2024-02-26  贝格前端工场    Tags:框架   点击:(47)  评论:(0)  加入收藏
Spring Security权限控制框架使用指南
在常用的后台管理系统中,通常都会有访问权限控制的需求,用于限制不同人员对于接口的访问能力,如果用户不具备指定的权限,则不能访问某些接口。本文将用 waynboot-mall 项目举例...【详细内容】
2024-02-19  程序员wayn  微信公众号  Tags:Spring   点击:(39)  评论:(0)  加入收藏
开发者的Kubernetes懒人指南
你可以将本文作为开发者快速了解 Kubernetes 的指南。从基础知识到更高级的主题,如 Helm Chart,以及所有这些如何影响你作为开发者。译自Kubernetes for Lazy Developers。作...【详细内容】
2024-02-01  云云众生s  微信公众号  Tags:Kubernetes   点击:(50)  评论:(0)  加入收藏
链世界:一种简单而有效的人类行为Agent模型强化学习框架
强化学习是一种机器学习的方法,它通过让智能体(Agent)与环境交互,从而学习如何选择最优的行动来最大化累积的奖励。强化学习在许多领域都有广泛的应用,例如游戏、机器人、自动驾...【详细内容】
2024-01-30  大噬元兽  微信公众号  Tags:框架   点击:(68)  评论:(0)  加入收藏
Spring实现Kafka重试Topic,真的太香了
概述Kafka的强大功能之一是每个分区都有一个Consumer的偏移值。该偏移值是消费者将读取的下一条消息的值。可以自动或手动增加该值。如果我们由于错误而无法处理消息并想重...【详细内容】
2024-01-26  HELLO程序员  微信公众号  Tags:Spring   点击:(86)  评论:(0)  加入收藏
SpringBoot如何实现缓存预热?
缓存预热是指在 Spring Boot 项目启动时,预先将数据加载到缓存系统(如 Redis)中的一种机制。那么问题来了,在 Spring Boot 项目启动之后,在什么时候?在哪里可以将数据加载到缓存系...【详细内容】
2024-01-19   Java中文社群  微信公众号  Tags:SpringBoot   点击:(86)  评论:(0)  加入收藏
花 15 分钟把 Express.js 搞明白,全栈没有那么难
Express 是老牌的 Node.js 框架,以简单和轻量著称,几行代码就可以启动一个 HTTP 服务器。市面上主流的 Node.js 框架,如 Egg.js、Nest.js 等都与 Express 息息相关。Express 框...【详细内容】
2024-01-16  程序员成功  微信公众号  Tags:Express.js   点击:(88)  评论:(0)  加入收藏
站内最新
站内热门
站内头条