深入Spring Boot配置机制:如何高效管理应用配置

news/2024/9/20 1:25:53/ 标签: spring boot, 后端, java

一、属性的优先级和配置文件的位置

在Spring Boot应用中,我们可以在多个地方定义配置属性,并且Spring Boot提供了一套优先级排序,来决定同一属性多处定义时的覆盖关系。理解这个机制对于配置管理至关重要。

1. 配置文件查找的顺序

Spring Boot在启动时会按照一定的顺序查找并加载配置文件,这个顺序大致如下:

  1. 首先从jar外部的/config子目录里的配置文件读取配置。
  2. 然后是jar相同目录下(./)的配置文件。
  3. 接着是jar内部的/config包里的配置文件。
  4. 最后是jar内部的配置文件(application.properties或application.yml)。

注:在同一目录级别中,优先加载后缀名为.yml或.yaml的文件,然后才是.properties文件。

2. 属性来源的优先级

Spring Boot的属性配置具有以下的优先级顺序,从最高优先级到最低优先级排序如下:

  1. 命令行参数
  2. 来自SPRING_APPLICATION_JSON的属性
  3. ServletConfig初始化参数
  4. ServletContext初始化参数
  5. JNDI属性
  6. Java系统属性(使用System.getProperties()获取)
  7. 操作系统环境变量
  8. 随机生成的 random.* 属性
  9. JAR包外部的application-{profile}.properties或application-{profile}.yml(带Spring profiles的配置)
  10. JAR包内部的application-{profile}.properties或application-{profile}.yml
  11. JAR包外部的application.properties和application.yml
  12. JAR包内部的application.properties和application.yml
  13. @Configuration类上的@PropertySource注解
  14. 默认属性(使用@Value时的默认值)

3. 外部配置的作用

外部配置可用于运行的应用程序,无需对代码进行任何更改。通过命令行参数、环境变量等,我们可以轻易地在不同环境间切换配置,这对于多环境部署非常有用。

二、使用application.properties或application.yml

Spring Boot的配置文件application.properties和application.yml在项目的资源目录下是极其常见的。这两个文件为应用的运行提供了必要的配置参数,并且Spring Boot在启动的时候会自动加载它们。

1. 基础配置读取实例

下面是如何在Spring Boot应用中读取properties配置的例子:

server.port=8080
app.name=MyApp

在Java代码中,我们可以使用@Value注解来读取这些值:

java">import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class AppConfig {@Value("${server.port}")private int serverPort;@Value("${app.name}")private String appName;// getter and setter methods
}

2. 配置文件分环境配置方法

通常,在开发、测试和生产等不同环境中,应用会有不同的配置需求。Spring Boot允许我们通过建立命名为application-{profile}.properties或application-{profile}.yml的文件来定义特定环境的配置。
例如,如果你有针对开发环境的特定配置,你可以创建一个application-dev.properties文件:

server.port=8081
app.debug=true

在启动Spring Boot应用时,可以通过下面的方式指定激活哪个profiles:

java -jar myapp.jar --spring.profiles.active=dev

这样就会加载application-dev.properties中的配置,同时application.properties中的配置也会被加载,但application-dev.properties的配置会覆盖application.properties的同名配置。

三、使用@Value注解读取配置

使用@Value注解是读取单个配置值的最直接方法。

1. 单个属性读取

以下是如何使用@Value注解来读取配置文件中的单个属性值的例子:

java">import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;@Component
public class ServiceProperties {@Value("${service.endpoint}")private String serviceEndpoint;// getter and setter if needed
}

在上面的代码中,${service.endpoint}将替换为在配置文件中指定的service.endpoint属性的值。如果该属性不存在,则注解的值会是一个空字符串。

2. 配置文件动态刷新

@Value注解并不支持动态更新配置,如果需要实现这样的功能,我们通常会结合Spring Cloud Config 或 Spring’s Environment抽象来使用。但如果项目中已经使用了@Value,我们可以使用@RefreshScope注解来标注需要动态配置的bean。例如:

java">import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;@Component
@RefreshScope
public class DynamicConfig {@Value("${dynamic.value}")private String dynamicValue;// getter and setter if needed
}

四、使用@ConfigurationProperties读取配置

@ConfigurationProperties注解是Spring Boot中用于强类型安全配置的替代方案,比@Value注解提供了更多的优势,如类型安全、松散绑定和复杂类型嵌套。

1. 绑定配置到POJO

通过创建一个带有@ConfigurationProperties注解的类,我们可以将配置项绑定到POJO的属性上。下面是一个例子:

app:mail:host: smtp.example.comport: 587from: no-reply@example.com
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Component
@ConfigurationProperties(prefix="app.mail")
public class MailProperties {private String host;private int port;private String from;// standard getters and setters
}

在上述例子中,@ConfigurationProperties(prefix=“app.mail”)指明了所有以app.mail为前缀的配置项都会绑定到相应的属性上。

2. 松散绑定与属性验证

松散绑定(Relaxed Binding)是Spring Boot的一个特性,它允许属性名的不完全匹配,例如在配置文件中定义app.mailPort,而在POJO类中则可以用mailPort或mail_port来绑定这个值。@ConfigurationProperties也支持JSR 303验证注解,比如@NotNull,你可以在你的配置POJO上添加校验注解来确保配置值满足某些条件,例如:

java">import org.springframework.validation.annotation.Validated;
import javax.validation.constraints.NotBlank;@Component
@ConfigurationProperties(prefix="app.user")
@Validated
public class UserProperties {@NotBlankprivate String username;// standard getters and setters
}

使用@Validated注解,可以确保在应用启动时如果配置项不符合验证条件,应用将不会启动,并提供错误提示。

五、使用@PropertySource注解读取指定配置

在Spring Boot中,默认情况下,配置是从application.properties或application.yml文件中读取的。但有时我们需要从其他资源位置加载配置,这时@PropertySource注解就显得非常有用。

1. 加载额外的配置文件

例如,你有一些特定的配置文件需要和主配置文件分开管理,这时可以创建一个带有@PropertySource注解的@Configuration类来指定配置文件的位置。下面是如何使用@PropertySource来加载指定配置的一个例子:

java">import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;@Configuration
@PropertySource("classpath:extras.properties")
public class ExtraConfig {// ...
}

@PropertySource注解中的字符串指向你的配置文件相对于类路径的位置。除了类路径之外,还可以使用file:(文件系统路径)或url:(访问网络资源)前缀来指定资源的位置。

2. 理解@PropertySource的使用场景

@PropertySource很适合用于加载不经常变动的基础配置,如数据库连接信息、客户端库配置等。此注解通常和@ConfigurationProperties搭配使用,用于在自定义配置类中指定多个配置文件。
需要注意的是,@PropertySource注解并不支持YAML格式的文件,它只能用于属性(properties)文件。如果需要加载YAML文件,你需要考虑其他方法,比如Spring Boot的配置文件分环境特性或使用Spring Cloud Config。

六、使用环境变量和命令行参数

在现代应用程序中,特别是在云环境和容器化部署中,使用环境变量和命令行参数来覆盖配置文件中的默认值变得越来越普遍。Spring Boot提供了灵活的支持,让这两种方式成为配置管理不可或缺的部分。

1. 读取系统环境变量

系统环境变量可以通过spring.environment属性或直接在application.properties/application.yml中使用通配符${VARIABLE_NAME}来读取。例如,如果你想通过环境变量来设置应用的端口,可以在application.yml中这样配置:

server:port: ${PORT:8080}

这里${PORT:8080}表示如果环境变量PORT被定义,其值将被用作服务器端口;如果未定义,将使用默认值8080。

2. 读取JVM系统属性

通过命令行启动Spring Boot应用时,可以通过-D标志设置JVM系统属性,这些属性也可以被用来覆盖配置。例如,你可以在启动应用时设置系统属性:

java -Dserver.port=8090 -jar myapp.jar

这将会覆盖application.properties中关于server.port的配置,使应用运行在8090端口上。

3. 读取命令行参数

命令行参数是通过应用启动时传递给main方法的参数,并且Spring Boot会自动解析这些参数以覆盖配置文件中的值。例如,启动应用时可以这样指定:

java -jar myapp.jar --server.port=8091

命令行参数的优先级高于环境变量,这意味着如果同时通过环境变量和命令行参数指定了配置,命令行参数会生效。
通过这些方式,Spring Boot应用可以轻松适应不同环境下的配置需求,无论是在本地开发还是在云平台上部署。

七、结合Cloud Config 读取远程配置文件

随着云原生应用的兴起,中心化管理应用配置成为了一种越来越受欢迎的实践。Spring Cloud Config为Spring Boot应用提供了一个解决方案,允许从远程位置(如Git仓库、文件系统等)统一管理配置文件,其它优秀的开源配置中心Apollo、Nacos也强烈推荐使用。

1. Spring Cloud Config 简介

Spring Cloud Config分为客户端和服务器两部分。服务器端存放集中化的配置文件,而客户端则是运行中的Spring Boot应用,它从Config Server读取配置。Config Server支持多种后端存储配置文件,其中最常见的是Git。
要使用Spring Cloud Config,首先需要搭建一个Config Server,并指定配置文件的存储位置。以下是一个简单的Config Server配置示例:

# application.yml of Config Server
spring:cloud:config:server:git:uri: https://github.com/example/config-repo.git

在客户端应用中,需要指定Config Server的位置:

# bootstrap.properties of Config Client
spring.cloud.config.uri=http://localhost:8888

客户端应用启动时,会从指定的Config Server读取配置。通过这种方式,可以在不重新部署服务的情况下,动态更改应用的配置。

2. 远程配置文件的读取和使用

为了确保你的Spring Boot应用从Spring Cloud Config Server正确加载配置,你需要在客户端应用的bootstrap.properties或bootstrap.yml文件中进行一些基础设置。这通常包括Config Server的URI、应用名等。然后,你可以像使用本地配置文件一样使用这些远程配置。Spring Cloud Config允许按环境分隔配置文件,你只需在客户端的bootstrap.properties文件中指定活动的profiles:

spring.application.name=myapp
spring.profiles.active=dev
spring.cloud.config.uri=http://localhost:8888

这样,当启动客户端应用时,它会从Config Server获取名为myapp-dev.yml或myapp-dev.properties的配置文件。

八、多配置文件的读取策略

在复杂的应用环境中,经常需要根据不同的环境(如开发、测试和生产)来分开管理配置文件。Spring Boot通过profiles提供了一种强大的方式来实现这一目标,同时也支持通过spring.config.import指令来合并多个配置文件。

1. @Profile注解在配置读取中的应用

Profiles为不同环境下的配置提供了一种条件化的方法。你可以创建专门针对某个环境的配置文件,例如application-dev.yml、application-test.yml等,并通过设置活动的profiles来激活相应的配置文件。
你也可以使用@Profile注解在代码级别定义配置的条件化,这允许你根据不同的环境来激活或禁用特定的Bean。例如:

java">import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;@Component
@Profile("dev")
public class DevDatabaseConfig {//...
}

这样,上面的DevDatabaseConfig类只有在“dev”profile被激活时才会被注册。

2. 使用spring.config.import指令

Spring Boot 2.4引入了spring.config.import属性,它提供了一种新的方式来合并和导入配置文件。使用这个属性,你可以轻松地引入其他配置文件或配置资源,它们可以是本地文件,也可以是远程位置的文件。你可以这样使用spring.config.import来引入额外的配置文件:

spring:config:import: classpath:extra-config.yml

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

相关文章

【debug记录】有gpu,但是 pytorch仍显示 cpu【原来是新电脑没安装cuda】

原来是新电脑没安装cuda,以为安装了pytorch包就可以了。 检查过程: nvcc 不是内部或外部命令,也不是可运行的程序, 说明没有安装cuda。 查看电脑显卡最高支持cuda版本:nvidia-smi 安装cuda,选择版本:ht…

基于小程序实现的查寝打卡系统

作者主页:Java码库 主营内容:SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】:Java 【框架】:ssm 【…

flink1.18.0 流转表 表转流 jdk17 attachAsDataStream

目的 流表互转 而且流sink 表sink同时存在且都可以输出. 依赖类 package flink.luca.flinkTableAndSQL.Convert;import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor;@Data @AllArgsConstructor @NoArgsConstructor public class Outer…

gcc/g++ 的使用

————gcc:只能编译c语言 ————g:c和c都可以编译 当然,c语言编译还是推荐gcc。 在学习gcc/g之前,我们要先了解一些知识点: 一、背景知识 1,预处理 gcc -E就是告诉编译器到预处理阶段就停下来&am…

QBoxLayout的addWidget(QWidget * w)会改变w的parent()

示例: 我希望在page_frame对象中使用orders_add_page对象的price变量, 但按照下面这样写得到的price的值都不对。 int price; orders_add_page::orders_add_page(QWidget *parent): QDialog(parent) {ui.setupUi(this);page new page_frame(type, t…

Windows10如何关闭Edge浏览器的Copilot

在Windows10更新后,打开Edge浏览器,无论复制什么内容,都会弹出Copilot人工智能插件,非常令人反感,网上搜索的关闭方法都非常麻烦,比如:组策略和注册表。自己摸索得出最简便有效的关闭方法。 1、…

go语言实现简单登陆样例

目录 1、代码实现样例: 2、postman调用,获取登陆后的token: 1、代码实现样例: package mainimport ("net/http""time""github.com/dgrijalva/jwt-go""github.com/gin-gonic/gin" )var …

【算法】约瑟夫环

文章目录 题目一1.数组模拟1.1出圈顺序递归求出圈顺序 1.2最后出圈人 2.环形链表【DEMO】3.递推求最后出圈人3.13.2 题目二1.数组模拟2.递推求最后出圈人2.12.2 题目一 1-n编号 s开始1-m报数 报到m出圈 求出圈顺序or最后人 1.数组模拟 1.1出圈顺序 递归求出圈顺序 // AC输入…

开源模型应用落地-LangChain高阶-集成vllm-QWen1.5(一)

一、前言 通过langchain框架调用本地模型,使得用户可以直接提出问题或发送指令,而无需担心具体的步骤或流程。vLLM是一个快速且易于使用的LLM推理和服务库。通过两者的结合,可以更好地处理对话,提供更智能、更准确的响应,从而提高对话系统的性能和用户体验。 二、术语 2.…

大语言模型微调过程中的 RLHF 和 RLAIF 有什么区别?

目前想要深入挖掘大型语言模型(LLM)的全部潜力需要模型与我们人类的目标和偏好保持一致。从而出现了两种方法:来自人类反馈的人力强化学习(RLHF)和来自人工智能反馈的人工智能驱动的强化学习(RLAIF&#xf…

服务器基础知识(2)

🐌博主主页:🐌​倔强的大蜗牛🐌​ 📚专栏分类:服务器❤️感谢大家点赞👍收藏⭐评论✍️ 一、如何选择服务器主机 选择服务器主机时,需要考虑以下几个关键因素: 用途和需…

MYSQL 8.0的Linux - Generic版本安装

1.本文适用范围 适用于MYSQL 8.0的Linux - Generic版本,原则上适用所有的操作系统。已测试的操作系统包括: Ubuntu 16.04Ubuntu 18.04Ubuntu 20.04Ubuntu 22.04Kylin Linux Advanced Server V10 ​ 注意:如果操作系统使用过包管理系统&…

JAVA toString方法详解

hi,我是程序员王也,一个资深Java开发工程师,平时十分热衷于技术副业变现和各种搞钱项目的程序员~,如果你也是,可以一起交流交流。 今天我们来聊聊Java中toString方法~ toString方法的定义 在Java中,toStri…

医院信创FTP要进行替代,有什么值得信赖的方案?

信创产业,即信息技术应用创新产业。其发展核心在于通过行业 应用拉动构建国产化信息技术软硬件底层架构体系和全生命周期生态体系,解决核心技术关键环节“卡脖子”的问题,为中国未来发展奠定坚实的数字基础。 2018 年 以来,受“华…

蓝桥杯2024年第十五届省赛真题-拔河

审题可能会遇到的问题&#xff1a;认为所有人都必须参与拔河&#xff0c;但其实不用&#xff0c;只要符合l1<r1<l2<r2就行&#xff0c;不一定要全部人上场&#xff0c;比如只上场a1和a2他们的力量差是1其实也可以。 正解思路&#xff1a;前缀和枚举二分。枚举左区间&…

MT8788智能模块简介_MTK联发科安卓核心板方案厂商

MT8788安卓核心板是一款具备超高性能和低功耗的4G全网通安卓智能模块。该模块采用联发科AIOT芯片平台&#xff0c;供货周期长。 MT8788核心板搭载了12nm制程的四个Cortex-A73处理器核心和四个Cortex-A53处理器核心&#xff0c;最高主频可达2.0GHz。板载内存容量可选为4GB64GB(也…

如何恢复已删除的微信联系人?

“您好&#xff0c;我删除了微信中的 5 个联系人。微信中已删除的联系人可以恢复吗&#xff1f;我使用的是 iPhone 15。” – 董奇 现在&#xff0c;越来越多的人使用微信应用程序与他人交流。微信中的联系人可能对我们来说非常重要。如果您误删了一些联系人&#xff0c;则必须…

Rust入门-引用借用

一、引用借用&#xff0c;是什么、为什么、怎么用 所有权上篇我们已经讨论过了&#xff0c;所以这篇我们讨论Rust的引用借用 1、引用借用 是什么&#xff1f; Rust 通过借用(Borrowing) 这个概念来达成上述的目的&#xff0c;获取变量的引用&#xff0c;称之为借用(borrowin…

Java | Leetcode Java题解之第48题旋转图像

题目&#xff1a; 题解&#xff1a; class Solution {public void rotate(int[][] matrix) {int n matrix.length;// 水平翻转for (int i 0; i < n / 2; i) {for (int j 0; j < n; j) {int temp matrix[i][j];matrix[i][j] matrix[n - i - 1][j];matrix[n - i - 1]…

【勒索病毒恢复】.svh勒索病毒介绍及恢复方案

一、.[[backupwaifu.club]].svh勒索病毒介绍 svh勒索病毒是一种恶意软件&#xff0c;它通过加密受害者的文件并要求支付赎金来解锁&#xff0c;从而达到勒索的目的。这种病毒已经存在了数年&#xff0c;并且不断演变&#xff0c;形成了多种不同的家族和变种。如果您的数据承载着…