springboot 获取application参数_LOOK ! SpringBoot的外部化配置最全解析

本篇要点

  • 介绍各种配置方式的优先级。
  • 介绍各种外部化配置方式。
  • 介绍yaml的格式及原理。
  • 介绍如何绑定并测试类型安全的属性配置。
  • 介绍@ConfigurationProperties与@Value的区别。

一、SpringBoot官方文档对于外部化配置的介绍及作用顺序

SpringBoot支持多种外部化配置,以便于开发者能够在不同的环境下,使用同一套应用程序代码。外部化配置的方式有多种:properties文件,yaml文件,Environment变量已经命令行参数等等。

外部化配置的属性值可以通过@Value注解自动注入,亦可以通过Spring的Environment抽象访问,也可以通过@ConfigurationProperties注解绑定到结构化对象上。

SpringBoot支持很多种的外部化配置,待会我们会介绍到。在这之前,我们必须要知道如果多种配置同时出现,一定是按照特定的顺序生效的。规则如下:

  1. devtool处于active状态时, $HOME/.config/spring-boot 目录中的Devtool全局配置。
  2. 测试中的@TestPropertySource注解。
  3. 测试中的@SpringBootTest#properties注解特性。
  4. 命令行参数。
  5. SPRING_APPLICATION_JSON 中的属性(环境变量或系统属性中的内联JSON嵌入)。
  6. ServletConfig 初始化参数。
  7. ServletContext 初始化参数。
  8. java:comp/env 里的JNDI属性
  9. JVM系统属性 System.getProperties() 。
  10. 操作系统环境变量
  11. 仅具有 random.* 属性的 RandomValuePropertySource 。
  12. 应用程序以外的application-{profile}.properties或者application-{profile}.yml文件
  13. 打包在应用程序内的application-{profile}.properties或者application-{profile}.yml文件
  14. 应用程序以外的application.properties或者appliaction.yml文件
  15. 打包在应用程序内的application.properties或者appliaction.yml文件
  16. @Configuration类上的@PropertySource注解,需要注意,在ApplicationContext刷新之前,是不会将这个类中的属性加到环境中的,像 logging.*,spring.main.* 之类的属性,在这里配置为时已晚。
  17. 默认属性(通过 SpringApplication.setDefaultProperties 指定).

这里列表按组优先级排序,也就是说, 任何在高优先级属性源里设置的属性都会覆盖低优先级的相同属性 ,列如我们上面提到的命令行属性就覆盖了application.properties的属性。

举个例子吧:

如果在application.properties中设置 name=天乔巴夏 ,此时我用命令行设置 java -jar hyh.jar --author.name=summerday ,最终的name值将会是summerday,因为命令行属性优先级更高。

二、各种外部化配置举例

1、随机值配置

配置文件中 ${random} 可以用来生成各种不同类型的随机值,从而简化了代码生成的麻烦,例如 生成 int 值、long 值或者 string 字符串。原理在于, RandomValuePropertySource 类重写了 getProperty 方法,判断以 random. 为前缀之后,进行了适当的处理。

my.secret=${random.value}my.number=${random.int}my.bignumber=${random.long}my.uuid=${random.uuid}my.lessThanTen=${random.int(10)}my.inRange=${random.int[1024,65536]}

2、命令行参数配置

默认情况下,SpringApplication将所有的命令行选项参数【以 -- 开头的参数,如 --server.port=9000 】转换为属性,并将它们加入SpringEnvironment中,命令行属性的配置始终优先于其他的属性配置。

如果你不希望将命令行属性添加到Environment中,可以使用 SpringApplication.setAddCommandLineProperties(false) 禁用它。

$ java -jar app.jar --debug=true #开启debug模式,这个在application.properties文件中定义debug=true是一样的

3、属性文件配置

属性文件配置这一部分是我们比较熟悉的了,我们在快速创建SpringBoot项目的时候,默认会在resources目录下生成一个application.properties文件。SpringApplication都会从配置文件加载配置的属性,并最终加入到Spring的Environment中。除了resources目录下,还有其他路径,SpringBoot默认是支持存放配置文件的。

/config/config

以上四个,优先级从上往下依次降低,也就是说,如果同时出现,上面配置的属性将会覆盖下面的。

关于配置文件,properties和yaml文件都能够满足配置的需求。

当然,这些配置都是灵活的,如果你不喜欢默认的配置文件命名或者默认的路径,你都可以进行配置:

$ java -jar myproject.jar --spring.config.name=myproject$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties

4、指定profile属性

通常情况下,我们开发的应用程序需要部署到不同的环境下,属性的配置自然也需要不同。如果每次在发布的时候替换配置文件,过于麻烦。SpringBoot的多环境配置为此提供了便利。具体做法如下:

我们之前在介绍各种配置的优先级的时候说过, application-{profile}.properties或者application-{profile}.yml文件 的优先级高于 application.properties或application.yml 配置,这里的profile就是我们定义的环境标识:

我们在resource目录下创建三个文件:

  • application.properties:默认的配置,default。
  • application-dev.properties:开发环境,dev。
  • application-prod.properties:生产环境,prod。

我们可以通过指定 spring.profiles.active 属性来激活对应的配置环境:

spring.profiles.active=dev

或使用命令行参数的配置形式:

$ java -jar hyh.jar --spring.profiles.active=dev

如果没有profile指定的文件于profile指定的文件的配置属性同时定义,那么指定profile的配置优先。

5、使用占位符

在使用application.properties中的值的时候,他们会从Environment中获取值,那就意味着,可以引用之前定义过的值,比如引用系统属性。具体做法如下:

name=天乔巴夏description=${name} is my name

6、加密属性

Spring Boot不提供对加密属性值的任何内置支持,但是,它提供了 修改Spring环境中的值 所必需的挂钩点。我们可以通过实现EnvironmentPostProcessor接口在应用程序启动之前操纵Environment。

可以参考 howto.html ,查看具体使用方法。

7、使用YAML代替properties

YAML是JSON的超集,是一种 指定层次结构配置数据的便捷格式 ,我们以properties文件对比一下就知道了:

#propertiesspring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8spring.datasource.username=rootspring.datasource.password=123456my.servers[0]=www.hyh.commy.servers[1]=www.yhy.com
# ymlspring:  datasource:    driver-class-name: com.mysql.cj.jdbc.Driver    url: jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8    username: root    password: 123456my:  server:    - www.hyh.com    - www.yhy.com

只要在类路径上具有SnakeYAML库,SpringApplication类就会自动支持YAML作为属性配置的方式。SpringBoot项目中的 spring-boot-starter 已经提供了相关类库: org.yaml.snakeyaml,因此SpringBoot天然支持这种方式配置。

关于yaml文件的格式,可以参考官方文档: Using YAML Instead of Properties

8、类型安全的属性配置

上面说到通过 @Value("${property}") 注解来注入配置有时会比较麻烦,特别是当多个属性本质上具有层次结构的时候。SpringBoot提供了一种解决方案: 让强类型的bean管理和验证你的配置

直接来看具体的使用叭:

@ConfigurationPropertie定义一个绑定配置的JavaBean

  1. 使用默认构造器+getter和setter注入
@ConfigurationProperties("acme")public class AcmeProperties {    private boolean enabled; //acme.enabled  默认为false    private InetAddress remoteAddress;// acme.remote-address  可以从String转换而来的类型    private final Security security = new Security();//.. 省略getter和setter方法    public static class Security {        private String username; // acme.security.username        private String password; // acme.security.password        private List roles = new ArrayList<>(Collections.singleton("USER"));// acme.security.roles//.. 省略getter setter方法    }}

这种方式依赖于默认的空构造函数,通过getter和setter方法赋值,因此getter和setter方法是必要的,且不支持静态属性的绑定。

如果嵌套pojo属性已经被初始化值: private final Security security = new Security(); 可以不需要setter方法。如果希望绑定器使用其默认构造函数动态创建实例,则需要setter。

  1. 通过@ContructorBinding注解使用构造器绑定的方式:
@ConstructorBinding //标注使用构造器绑定@ConfigurationProperties("acme")public class AcmeProperties {    private final Security security;    private final boolean enabled;    private final InetAddress remoteAddress;    public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {        this.enabled = enabled;        this.remoteAddress = remoteAddress;        this.security = security;    }    //..省略getter方法    @ToString    public static class Security {        private final String username;        private final String password;        private final List roles;        public Security(String username, String password,                        @DefaultValue("USER") List roles) {            this.username = username;            this.password = password;            this.roles = roles;        }    }    //..省略getter方法}

如果没有配置Security实例属性,那么最后结果:Security=null。如果我们想让Security={username=null,password=null,roles=[USER]},可以在Security上加上@DefaultValue。 public AcmeProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security)

通过@EnableConfigurationProperties注册

已经定义好了JavaBean,并与配置属性绑定完成,接着需要注册这些bean。我们通常用的@Component或@Bean,@Import加载bean的方式在这里是不可取的,SpringBoot提供了解决方案: 使用@EnableConfigurationProperties ,我们既可以一一指定配置的类,也可以按照组件扫描的方式进行配置。

@SpringBootApplication@EnableConfigurationProperties({HyhConfigurationProperties.class, MyProperties.class,AcmeProperties.class})public class SpringBootProfileApplication {}
@SpringBootApplication@ConfigurationPropertiesScan({"com.hyh.config"})public class SpringBootProfileApplication {}

配置yaml文件

acme:  remote-address: 192.168.1.1  security:    username: admin    roles:      - USER      - ADMIN

注入properties,测试

@Configurationpublic class Application implements CommandLineRunner {    @Autowired    private AcmeProperties acmeProperties;    @Override    public void run(String... args) throws Exception {        System.out.println(acmeProperties);    }}
//输出: AcmeProperties(security=AcmeProperties.Security(username=admin, password=null, roles=[USER, ADMIN]), enabled=false, remoteAddress=/192.168.1.1)

宽松绑定

SpringBoot采用宽松的规则进行Environment和@ConfigurationProperties标注bean的匹配。如:

@ConfigurationProperties(prefix="acme.my-project.person")public class OwnerProperties {    private String firstName;    public String getFirstName() {        return this.firstName;    }    public void setFirstName(String firstName) {        this.firstName = firstName;    }}

下面表格中的属性名都可以匹配:

a8f0185f12fcb01ceeb1aae9c05c1388.png

@ConfigurationProperties注解中的prefix值必须是kebab case形式的,以 - 为分割符。

Spring官方建议,属性尽可能以lower-case kebab的形式:my.property-name=acme

Map如何绑定

绑定到Map属性时,如果key包含 小写字母数字字符或-以外的任何其他字符 ,则需要使用方括号包围key,以便保留原始值。 如果键没有被 [] 包围,则所有非字母数字或-的字符都将被删除。如下:

hyh:  username: 天乔巴夏  password: 123456  map:    "[/key1]": value1 #用引号包围[],用[]包围key    /key3: value3    key-4: value4    key/5: value5# 结果:"map":{/key1=value1,key5=value5, key-4=value4, key3=value3}

环境变量如何绑定

遵循三条原则:

  1. 把 . 换成下划线 _ 。
  2. 移除 - 。
  3. 小写转大写。

如: spring.main.log-startup-info 转为: SPRING_MAIN_LOGSTARTUPINFO , my.acme[0].other 转为 MY_ACME_0_OTHER 。

9、复杂类型

之前介绍yml文件,介绍了单纯的数组形式或值的绑定,SpringBoot还支持复杂类型的绑定。

merge:  list:    - name: 天乔巴夏      desc: 帅啊    - name: tqbx      desc: 很帅啊  map:    key1:      name: summerday      desc: handsome!    key2:      name: summer
@ToString@ConfigurationProperties(prefix = "merge")public class MergeProperties {    private final List list = new ArrayList<>();    private final Map map = new HashMap<>();    public List getList() {        return list;    }    public Map getMap() {        return map;    }}

最后输出:

MergeProperties(    list=[User(name=天乔巴夏, desc=帅啊),           User(name=tqbx, desc=很帅啊)],     map={key1=User(name=summerday, desc=handsome!),          key2=User(name=summer, desc=null)}a)

10、参数校验

对@ConfigurationProperties类使用Spring的 @Valid 注解时,Spring Boot就会尝试对其进行验证。

你可以直接在配置类上使用JSR-303 javax.validation 约束注解。这个做法的前提是,你的类路径上有兼容的JSR-303实现:

org.hibernate            hibernate-validator            6.0.18.Final

然后将约束注解加到字段上,如下:

@Data@Validated@ConfigurationProperties(prefix = "validate")public class ValidateProperties {    @NotNull    private String name;    @Valid    private final SubProperties subProperties = new SubProperties();    @Data    public static class SubProperties {        @Min(value = 10,message = "年龄最小为10")        public Integer age;    }}

配置如下:

validate:  name: hyh  sub-properties:    age: 5

结果如下:

Description:Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'validate' to com.hyh.config.ValidateProperties failed:    Property: validate.sub-properties.age    Value: 5    Origin: class path resource [application.yml]:47:10    Reason: 年龄最小为10        Action:Update your application's configuration

三、@ConfigurationProperties与@Value的区别

@Value注解是一个核心容器功能,它没有提供和type-safe配置属性相关的功能,下面这个表格总结了两者分别支持的功能:

96032258c3ee0e078d333e93e399be51.png

官方建议:

  • 如果你为自己的组件定义了一套配置,建议使用@ConfigurationProperties和POJO绑定,这样做能够提供结构化且类型安全的对象。
  • 如果硬要使用@Value,建议使用kebab-case形式,如@Value(" ${demo.item-price}")

来源:https://www.tuicool.com/articles/uQFFBzz

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

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

相关文章

spark入门_入门必读 | Spark 论文导读

Resilient Distributed Datasets: A fault-tolerant abstraction for in-Memory cluster computing&#xff0c; 是讲述 Spark RDD 的基础论文&#xff0c;通读论文能给我们带来全景的 Spark 知识面摘要&#xff1a;RDD,全称Resilient Distributed Dataset,可伸缩性数据集。使用…

Qt在linux下无法输入中文,Ubuntu使用集成开发环境QT无法输入中文的解决方法

QT Creator是轻量级集成开发环境&#xff0c;在Ubuntu系统操作中&#xff0c;使用QT时无法输入中文&#xff0c;遇到这种情况要如何处理呢&#xff1f;下面小编就给大家介绍下Ubuntu如何解决QT无法输入中文问题。1 安装搜狗输入法&#xff0c;(如果你想用ubuntu自带的输入法也没…

altium pcb 信号高亮_在PCB设计中高效的放置元件技巧

在印刷电路板设计中&#xff0c;设置电路板轮廓后&#xff0c;将零件(占地面积)调用到工作区。然后将零件重新放置到正确的位置&#xff0c;并在完成后进行接线。组件放置是这项工作的第一步&#xff0c;对于之后的平滑布线工作是非常重要的工作。如果在接线工作期间模块不足&a…

linux升级ssh到6.6版本,CentOS6.5 openssh升级到openssh-7.6版本

CentOS6.5 openssh升级到openssh-7.6版本2018-8-3 foooy升级前保证故障后能现场处理&#xff0c;或者远程卡处理&#xff0c;否则不要这样直接升级yum install -y gcc openssl-devel pam-devel rpm-buildwget http://ftp.openbsd.org/pub/OpenBSD/OpenSSH/portable/openssh-7.6…

python中csv文件通过什么表示字符_python_写入csv文件时候无法进行原样写入(写入字符串中出现逗号,时候,csv文件自动分成两个单元格)...

问题描述&#xff1a; 写入csv文件时候无法进行原样写入(写入字符串中出现逗号","时候&#xff0c;csv文件自动分成两个单元格) with open("test.csv","w") as f: f.write("闲暇时&#xff0c;我会被一段&#xff0c;配乐诗朗诵,所感动,悲伤…

rabbitmq怎样确认是否已经消费了消息_阿里Java研发二面:了解RabbitMQ?说说RabbitMQ可靠性投递...

上期写到高并发下RabbitMq消息中间件你应该介么玩今天给小伙伴说说&#xff01;有自己看法的也可以在评论区留言探讨&#xff0c;也可以转发关注下我以后会长期分享&#xff01;目录&#xff1a;确保消息发送到RabbitMQ服务器确保消息被正确的路由确保消息在队列正确地存储确保…

linux 装完yum不能用,【linux】yum 不能安装应用,提示There are no enabled repos Run “yum repolist all”...

回答一般来说著名的linux系统基本上分两大类&#xff1a;1 RedHat系列&#xff1a;Redhat、Centos、Fedora等2 Debian系列&#xff1a;Debian、Ubuntu等RedHat 系列&#xff1a;1 常见的安装包格式 rpm 包&#xff0c;安装rpm包的命令是 “rpm -参数”2 包管理工具 yum3 支持ta…

更新fielddata为true_线程与更新UI,细谈原理

前言 相信不少读者都阅读过相类似的文章了&#xff0c;但是我还是想完整的把这之间的关系梳理清楚&#xff0c;细节聊好&#xff0c;希望你也能从中学到一些。进入正题&#xff0c;大家应该都听过这样一句话——“UI更新要在主线程&#xff0c;子线程更新UI会崩溃”。久而久之就…

linux sublime3 插件安装插件,手动安装sublimeText3插件

就在今天下午&#xff0c;我花了一个小时的时间安装sublime3插件stylus&#xff0c;就是为了让stylus文件能够高亮显示。网上找了很多方法&#xff0c;可以通过package control安装&#xff0c;然而&#xff0c;我的sublime package control能够正常显示&#xff0c;插件列表也…

vbs打开软件光标停在第一个输入框_三维设计软件,3DMAX最全快捷键大全,赶快收藏哦...

文章后有获取软件的方式。基本快捷键A-角度捕捉开关 B-切换到底视图C-切换到摄象机视图D-封闭视窗E-切换到轨迹视图F-切换到前视图G-切换到网格视图H-显示通过名称选择对话框I-交互式平移J-选择框显示切换K-切换到背视图L-切换到左视图M-材质编辑器N-动画模式开关O-自适应退化开…

mfc读取txt文件并显示_Python入门丨文件读写

文件读写文件读写&#xff0c;是Python代码调用调用电脑文件的主要功能&#xff0c;能被用于读取和写入文本记录、音频片段、Excel文档、保存邮件以及任何保存在电脑上的东西。读取文件读取文件三个步骤&#xff1a;准备工作&#xff1a;首先在桌面新建了一个test文件夹&#x…

c语言 多个线程对同一变量执行memcpy_手把手带你实现线程池

执行与任务分离的组件— 线程池wangbojing/threadpool​github.com多线程技术主要解决了处理器单元内多个线程执行的问题&#xff0c;它可以显著的减少处理器单元的闲置时间&#xff0c;增加处理器单元的吞吐能力。线程池是多线程编程的一个必要组件&#xff0c;并且对于很多编…

python手势识别_Python|使用opencv进行简单的手势检测

简单的手势识别&#xff0c;基本思路是基于皮肤检测&#xff0c;皮肤的颜色在HSV颜色空间下与周围环境的区分度更高&#xff0c;从RGB转换到HSV颜色空间下针对皮肤颜色进行二值化&#xff0c;得到mask&#xff1a; defHSVBin(img):hsvcv2.cvtColor(img,cv2.COLOR_RGB2HSV) lowe…

人工智能选go还是python_深圳人工智能学Python还是go,真实经历分享

深圳人工智能学Python还是go&#xff0c;进行选择深圳Python培训 的时候&#xff0c;第一要思考的就是该机构的口碑如何。如果该家机构没有一定的口碑信誉&#xff0c;就等于搬起石头砸了自己的招牌。为什么突然就那么火了&#xff0c;Python的工资待遇&#xff0c;人工智能&am…

python做excel数据分析统计服_Python也能做到Excel那样,条件统计轻松解决工作需求...

此系列文章收录在公众号中&#xff1a;数据大宇宙 > 数据处理 >E-pd 转发本文并私信我"python"&#xff0c;即可获得Python资料以及更多系列文章(持续更新的) 经常听别人说 Python 在数据领域有多厉害&#xff0c;结果学了很长时间&#xff0c;连数据处理都麻烦…

java贪吃蛇_如何用Java还原童年回忆?在线教你完成贪吃蛇小游戏

今天我就从零开始来完成这个小游戏&#xff0c;完成的方式也是一步一步的添加功能这样的方式来实现。额&#xff0c;不好意思&#xff0c;放错了&#xff0c;重来第一步完成的功能&#xff1a;写一个界面大家见到的贪吃蛇小游戏&#xff0c;界面肯定是少不了的。因此&#xff0…

jtextpane设置不能选中_在Bridge cc中不能使用camera raw 的编辑功能,解决方法

有时我们在Bridge cc中想对raw文件进行处理&#xff0c;这时需要启动camera raw功能&#xff0c;可是当我们启用时却显示不能编辑&#xff0c;下面说下如何启动使用camera raw 的编辑功能1.打开一张raw格式文件&#xff0c;在文件菜单或者右键选择在camera raw中打开&#xff0…

android icon命名规则,安卓手机的APP图标尺寸规范和图标命名规范

安卓手机的APP图标尺寸规范和图标命名规范点击查看原文android图标包括&#xff1a;程序启动图标、底部菜单图标、弹出对话框顶部图标、长列表内部列表项图标、底部和底部tab标签图标。1、安卓程序启动图标尺寸&#xff1a;ldpi(120dpi)小屏幕mdpi(160dpi)中屏幕hdpi(240dpi)大…

opencv python教程简书_Python-OpenCV —— 基本操作一网打尽

OpenCV是一个基于BSD许可&#xff08;开源&#xff09;发行的跨平台计算机视觉库&#xff0c;可以运行在Linux、Windows、MacOS操作系统上。它轻量级而且高效——由一系列 C 函数和少量C类构成&#xff0c;同时提供了Python、Ruby、MATLAB等语言的接口&#xff0c;实现了图像处…

opengles 顶点数组 android,OpenGLES顶点属性、顶点数组和缓冲区对象

顶点属性数据可以用一个顶点数组对每个顶点指定&#xff0c;也可以将一个常量值用于一个图元的所有顶点OpenGLES支持最少16个顶点属性。准确查询顶点数量方法如下&#xff1a;GLint maxVertexAttribs;glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &maxVertexAttribs);一、指定顶点…