0x04 Spring Boot 2.x之Properties和yaml配置文件详解

1. 外部化配置

Spring 支持外部化配置,比如application.properties 文件,application.yml,环境变量,命令行参数等。

1.1 配置随机数

1.1.1 application.properties 配置如下

my.secret=${random.value}
my.number=${random.int}
my.bignumber=${random.long}
my.uuid=${random.uuid}
my.number.less.than.ten=${random.int(10)}
my.number.in.range=${random.int[1024,65536]}

random.int 语法如下所示:
比如:random.int [1024,65536]
1024是最小值,65536最大值
再比如: random.int(10) 表示小于10的整数

1.1.2 Controller 中这样调用

HomeController.java

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

import java.math.BigInteger;

@RestController
public class HomeController {
    @Value(value = "${my.secret}")
    private String mySecret;

    @Value(value = "${my.number}")
    private Integer myNumber;

   @Value(value = "${my.bignumber}")
   private BigInteger myBigNumber;

   @Value(value = "${my.uuid}")
   private String uuid;

   @Value(value ="${my.number.less.than.ten}")
   private String myNumberLessThanTen;

   @Value(value = "${my.number.in.range}")
   private String myNumberInRange;

    @GetMapping(value = "/test.do")
    public String test(){

        StringBuilder sb=new StringBuilder();

        sb.append("my.secret:"+mySecret);
        sb.append("--------------------");
        sb.append("my.number:"+myNumber);
        sb.append("--------------------");
        sb.append("myBigNumber:"+mySecret);
        sb.append("--------------------");
        sb.append("my.uuid:"+uuid);
        sb.append("--------------------");
        sb.append("my.number.less.than.ten:"+myNumberLessThanTen);
        sb.append("--------------------");
        sb.append("my.number.in.range:"+myNumberInRange);
        sb.append("--------------------");

        String result=sb.toString();
        return result;
    }
}

访问效果:
在这里插入图片描述

1.2 访问命令行属性

比如application.properties 文件中有如下配置

server.port=8080

我们在运行的时候可以动态修改这个端口属性,通过–参数的方法。
比如这里我们可以使用–server.port 来覆盖application.properties 文件中的配置。
执行命令如下:

java -jar .\spring-boot-2-x-externalized-configuration-sample-0.0.1-SNAPSHOT.jar
 --server.port=8081

执行成功后,端口就成功修改成了8081端口,而不是默认的8080端口

因为命令行属性始终优先于其他属性源

如果想要禁用这个命令行参数运行,设置这一行代码即可。

springApplication.setAddCommandLineProperties(false);

完整配置范例如下:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBoot2XExternalizedConfigurationSampleApplication {

    public static void main(String[] args) {

        //SpringApplication.run(SpringBoot2XExternalizedConfigurationSampleApplication.class, args);

        SpringApplication springApplication=new SpringApplication(SpringBoot2XExternalizedConfigurationSampleApplication.class);
        springApplication.setAddCommandLineProperties(false);
        springApplication.run(args);

    }
}

1.3 Application Property 文件

SpringApplication 加载application.properties 文件,从下面这几个位置中查找

  • ./config
  • ./
  • classpath:/config/
  • classpath:/

按照这个列表中位置的优先级,优先级高的会覆盖优先级低的配置文件。
也可以通过命令行参数来动态加载单个配置文件

java -jar myproject.jar --spring.config.name=myproject

如果要加载两个配置文件就这么做:

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

如果spring.config.location包含目录(而不是文件),它们应该以 / 结束

默认情况下,配置文件的查找顺序是这样:

  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/

当指定了spring.config.location 之后,查找顺序就改变了。

  • file:./custom-config/
  • classpath:custom-config/classpath:custom-config/

当然我们也可以即保留默认值,然后额外地添加配置文件路径
classpath:/custom-config/,file:./custom-config/这两个额外的配置添加后,查找顺序就变成了这样:

  • file:./custom-config/
  • classpath:custom-config/
  • file:./config/
  • file:./
  • classpath:/config/
  • classpath:/

1.4 Profile-specific Properties

由于开发,测试,生产环境有些地方需要不同的配置,因此Spring Boot 也提供了一种解决方案。
application-{profile}.properties
一般我们经常这么设置

  • application.properties ---------写公共配置
  • application-dev.properties-------写开发环境配置
  • application-test.properties------写测试环境配置
  • application-prod.properties-----写生产环境配置

假设我们想使用开发环境的配置就在application.properties 文件中指定这个属性

spring.profiles.active=dev

程序运行就会加载application.properties 和application-dev.properties 两个配置文件中的配置。
如果想切换到测试环境配置就修改为:

spring.profiles.active=test

程序运行就会加载application.properties 和application-test.properties 两个配置

1.5 Properties 文件中的占位符

application.properties 文件配置如下:

app.name=MyApp
app.description=${app.name} is a Spring Boot application

Controller 中调用如下

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

import java.math.BigInteger;

@RestController
public class HomeController {

    @GetMapping(value = "/")
    public String home(){
        return "Hello World Spring Boot 2.x";
    }

    @Value(value = "${app.name}")
    private String appName;

    @Value(value = "${app.description}")
    private String appDescription;

    @GetMapping(value = "/test.do")
    public String test(){

        StringBuilder sb=new StringBuilder();

        sb.append("appName:"+appName);
        sb.append("-------------------");
        sb.append("appDescription:"+appDescription);
        sb.append("-------------------");
        String result=sb.toString();
        return result;
    }
}

访问结果
在这里插入图片描述

1.6 加密属性值

Spring Boot没有为加密属性值提供任何内置支持
如果您正在寻找一种存储凭据和密码的安全方法, Spring Cloud Vault项目支持在HashiCorp Vault中存储外部化配置 。

1.7 使用yaml 文件替换properties 文件

YAML是JSON的超集,因此是用于指定分层配置数据的便捷格式。该SpringApplication级自动支持YAML来替代,只要你有属性 SnakeYAML在classpath库。

如果您使用“Starters”,则会自动提供SnakeYAML spring-boot-starter

1.7.1 YAML 文件的加载详解

Spring Framework 提供了两个类来加载YAMl 文件
YamlPropertiesFactoryBean将YMAL 文件转换成Properties 文件
YamlMapFactoryBean 再将Properties中的值 保存到Map里面
比如application.yaml 文件配置如下

environments:
	dev:
		url: http://dev.example.com
		name: Developer Setup
	prod:
		url: http://another.example.com
		name: My Cool App

它会首先转换成

environments.dev.url=http://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=http://another.example.com
environments.prod.name=My Cool App

比如这个配置文件

my:
servers:
	- dev.example.com
	- another.example.com

它会解析成这样

my.servers[0]=dev.example.com
my.servers[1]=another.example.com

然后还用了一个配置类

@ConfigurationProperties(prefix="my")
public class Config {

	private List<String> servers = new ArrayList<String>();

	public List<String> getServers() {
		return this.servers;
	}
}

注意:一旦使用@ConfigurationProperties自定义属性值注解,则需要添加下面这个依赖

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

1.7.2 YAML 文件也支持@Value注解

yaml 文件也支持@value 注解来访问yaml 文件中的配置属性值。
它是再YamlPropertySourceLoader这个类的帮助下实现的。

1.7.3 多个YAML 文件

举个例子

server:
	address: 192.168.1.100
---
spring:
	profiles: development
server:
	address: 127.0.0.1
---
spring:
	profiles: production & eu-central
server:
	address: 192.168.1.120

如果是development 文件被激活,那么server.address就使用127.0.0.1,如果
production & eu-central 文件被激活,那么server.address就使用192.168.1.120.如果都没有激活,则server.address使用默认的192.168.100

1.7.4 Properties 属性值类型安全

我们可以再Properties 文件里面配置自定义属性,但是似乎存在一定安全隐患,比如application.properties 文件中配置如下

acm.enabled=true

这个true 是Boolean 类型还是字符串类型呢?显然并没有做限制,这样是不太好的。
为了对这个属性值的数据类型做一定的约束,我们需要这么做:
AcmeProperties.java

package com.example;

import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties("acme")
public class AcmeProperties {

	private boolean enabled;

	private InetAddress remoteAddress;

	private final Security security = new Security();

	public boolean isEnabled() { ... }

	public void setEnabled(boolean enabled) { ... }

	public InetAddress getRemoteAddress() { ... }

	public void setRemoteAddress(InetAddress remoteAddress) { ... }

	public Security getSecurity() { ... }

	public static class Security {

		private String username;

		private String password;

		private List<String> roles = new ArrayList<>(Collections.singleton("USER"));

		public String getUsername() { ... }

		public void setUsername(String username) { ... }

		public String getPassword() { ... }

		public void setPassword(String password) { ... }

		public List<String> getRoles() { ... }

		public void setRoles(List<String> roles) { ... }

	}
}

注意:一旦使用@ConfigurationProperties自定义属性值注解,则需要添加下面这个依赖

<dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-configuration-processor</artifactId>
        <optional>true</optional>
    </dependency>

其次还需要在有Configuration注解的类中添加这个属性类配置

@Configuration
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}

1.7.5 第三方的配置

@ConfigurationProperties 和Bean 组合使用来配置第三方库也是非常有帮助的。

@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
	...
}

1.7.6 @ConfigurationProperties 验证

Properties 文件中的属性值,有时候我们想添加一些验证,那么如何做呢?
首先需要类级别上添加@Validated 注解,其次在属性值上使用@NotNull 注解,@Valid@NotEmpty注解等

@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {

	@NotNull
	private InetAddress remoteAddress;

	@Valid
	private final Security security = new Security();

	// ... getters and setters

	public static class Security {

		@NotEmpty
		public String username;

		// ... getters and setters

	}

}

1.7.7 自定义属性值最佳实践

虽然Spring Boot 仍然支持@Value注解访问application.properties 文件中自定义的属性值,但是该方法已经过时,不推荐使用。
最佳实践如下:

  1. applicaton.properties配置如下:
com.xingyun.config.username=xingyun
com.xingyun.config.age=27
com.xiingyun.config.sex=boy
  1. 创建一个叫做CustomProperties.Java 文件
@ConfigurationProperties(prefix="com.xingyun.config")
public class CustomProperties{
      private String username;
      private Integer age;
      private String sex;
      //getter and setter ...
}
  1. 在一个带有@Configuration 注解的类上添加@EnableConfigurationProperties(CustomProperties.class)注解配置
@EnableConfigurationProperties(BrdPicProperties.class)
@Configuration
public class MyConfig {
}
  1. 在需要使用的地方,使用@Autowired 注解CustomProperties 配置如下:
public class MyService{
      @Autowired
      CustomProperties  customProperties;

      pullic void  testMethod(){
           System.out.println(customProperties.getUserName());
           System.out.println(customProperties.getAge());
           System.out.println(customProperties.getSex());
     }
}

本篇完~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值