转载

【Java】spring boot 2.0特性之外部化配置

简介

spring boot允许你外部化其配置以便你能够在不同的环境中使用相同的代码。可以通过使用properties, YAML  文件,环境变量,以及命名行参数等形式外部化其配置。属性值可以通过@value的形式直接注入到bean中去(其通过spring 的抽象或者是通过使用 @ConfigurationProperties绑定其结构化对象

spring boot使用了一种特别的   PropertySource 允许你覆盖其值,其覆盖顺序如下:

1. devtools的环境变量被设置,则优先使用(其 ( ~/.spring-boot-devtools.properties  被设置,并且被激活

2. 在测试的类上设置了 @TestPropertySource

3. 在测试类上使用 @SpringBootTest#properties  注解了属性

4. 命名行参数

5. 来自于 SPRING_APPLICATION_JSON 属性。

6.  ServletConfig  初始化参数

7.  ServletContext  初始化参数

8. 来自于 java:comp/env .的JNDI属性

9. java系统属性( System.getProperties()

10. 操作系统变量

11. 仅仅在 System.getProperties()里面的   RandomValuePropertySource  。

12. 在jar包外部配置的指定应用属性外部变量属性( application-{profile}.properties  与 YAML 变量

13. 在jar包内指定应用 属性 的变量( application-{profile}.properties  与 YAML 变量

14. 在jar包外部指定的应用变量 application.properties  与 YAML 变量

15. 在jar包内指定的应用变量( application.properties  与 YAML 变量

16. 在   @Configuration 类上使用 @PropertySource  的标签

17. 默认的属性(使用   SpringApplication.setDefaultProperties指定

以下是一个简单的例子:假定使用name属性开发一个 @Component,具体代码如下

import org.springframework.stereotype.*
import org.springframework.beans.factory.annotation.*

@Component
public class MyBean {

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

    // ...

}
在应用根路径上,可以提供一个 application.properties

指定默认的环境变量。当运行一个新的环境变量的时候,可以通过指定application.properties覆盖name的值。对于一次性测试,可以通过命名行发送指定的变量,例如代码如下:

java -jar app.jar --name="Spring"
可以在linux命名行中指定环 SPRING_APPLICATION_JSON  

环境变量:代码如下:

SPRING_APPLICATION_JSON='{"acme":{"name":"test"}}' java -jar myapp.jar

也可以通过如下方式:

java -Dspring.application.json='{"name":"test"}' -jar myapp.jar

也可以通过命名行的形式:

java -jar myapp.jar --spring.application.json='{"name":"test"}'

配置随机变量

RandomValuePropertySource  主要是用于注入随机变量。其能够生成

integers, longs, uuids 或者是 strings类型:如下代码所示

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*可以指定区间范围,既最大值与最小值的区间范围。

链接命名行属性

默认情况下, SpringApplication  会转化任何命名行的参数(其参数通过“--”开始)为属性并将其添加到spring的环境变量中。命名行的参数总是优先覆盖其他来源的参数。

如果不想让其加入到spring的环境变量中,可以通过如下代码方式禁止:

SpringApplication.setAddCommandLineProperties(false).

应用属性文件

SpringApplication  将会从如下位置加载application.properties到spring的环境变量中:

1. 当前目录的子目录 /config下

2. 当前目录

3. 类路径的 /config下

4. 应用根目录下

上述也是其优先使用顺序。

如果不想使用 application.properties 作为其配置文件名字,可以通过配置环境变量 spring.config.name 进行设置。也可以通过具体化位置的环境变量 spring.config.location 其指定:如下代码

#通过第一种方式 
java -jar myproject.jar --spring.config.name=myproject
##方式二
 java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
如果 spring.config.location  也包含具体目录,需要使用“/”.   spring.config.location  不支持具体额配置环境变量,将会被默认的配置环境变量替换。其配置搜索的顺序与配置的顺序刚好相反。例如:配置顺序为: classpath:/,classpath:/config/,file:./,file:./config/,其搜索顺序如下:
  1. file:./config/
  2. file:./
  3. classpath:/config/
  4. classpath:/

如果配置 spring.config.additional-location属性,将其追加默认的位置。追加的位置是在默认的位置之前进行搜索。例如追加的目录为   classpath:/custom-config/,file:./custom-config/, 其搜索的顺序如下:

  1. file:./custom-config/
  2. classpath:custom-config/
  3. file:./config/
  4. file:./
  5. classpath:/config/
  6. classpath:/

(备注,我们也可以通过配置环境变量的形式来进行配置)

特定环境配置属性(profile-specific)

作为附件的 application.properties 文件, profile-specific 属性可以通过使用方便的命名 application-{profile}.properties 进行定义。如果没有特定的环境配置被激活,其环境变量将采用默认的一系列的配置进行。换句话说,就是没有配置被激活,将采用默认的 application.properties文件。

Profile-specific属性默认从标准的application.properties中加载。不管其 profile-specific指定的 文件是在外部还是内部,其总是被加载。

属性中的占位符

我们可以在在统一属性文件中调用之前定义的变量:代码如下:

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

使用YAML代替属性

YAML是json的一个超级子集,非常方便形成一个层次结构的配置文件。 SpringApplication   默认支持YAML的配置。yaml默认被 spring-boot-starter支持。

01. 加载YAML

spring框架默认提供了2中方式加载YAML配置,使用 YamlPropertiesFactoryBean 作为一个属性加载YAML与使用 YamlMapFactoryBean   作为一个MAP加载YAML。

例如如下的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

yaml的列表可以通过{index}的方式应用:如下列子:

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

被转换为属性之后的结果为:

my.servers[0]=dev.example.com
my.servers[1]=another.example.com
通过使用   DataBinder

工具绑定变量的时候,在被绑定的类上必须要有一个List的类或者是set,提供一个setter方法,如下代码:

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

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

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

02. 在spring的环境中暴露yaml属性

其主要通过 YamlPropertySourceLoader   去暴露。

03. 多配置环境的yaml文档

可以通过 spring.profiles

去指定该用哪一个环境变量:如下代码

server:
	address: 192.168.1.100
---
spring:
	profiles: development
server:
	address: 127.0.0.1
---
spring:
	profiles: production
server:
	address: 192.168.1.120
上述环境中,如果开发环境被触发:则sever地址为: 127.0.0.1,如果为生产地址:则地址为   192.168.1.120 .,当其两个都不可用的时候,默认为 192.168.1.100。

环境

04. YAML的不足

其不能通过@ PropertySource  进行加载

05. 合并YAML列表

按照前面所讲,任何yaml都会被转换为属性,当其列表有重复的时候可能会有问题的:如下代码

@ConfigurationProperties("acme")
public class AcmeProperties {

	private final List<MyPojo> list = new ArrayList<>();

	public List<MyPojo> getList() {
		return this.list;
	}

}
-----------------------------------------------
acme:
  list:
    - name: my name
      description: my description
---
spring:
  profiles: dev
acme:
  list:
       - name: my another name
如果 dev   没有被激活,则只包含一个元素 MyPojo  ,如果   dev

被激活,其仍然只包含一个元素,其不会添加第二个元素进去,其没有合并其项。当其要进行合并的时候,必须要指定一个高亮的:如下代码所示:

acme:
  list:
	- name: my name
	  description: my description
	- name: another name
	  description: another description
---
spring:
  profiles: dev
acme:
  list:
	 - name: my another name

上述代码中的第一个list所示

acme:
  list:
	- name: my name
	  description: my description
	- name: another name
	  description: another description
---
spring:
  profiles: dev
acme:
  list:
	 - name: my another name

类型安全的配置属性

使用   @Value("${property}")  注入配置属性有时候是使笨重的,特别是有多个属性或者是数据本质上有层级关系的。 Spring Boot提供了一种可选的方法:让安全的bean管理和验证器应用程序:如下例子:

通过使用   @EnableConfigurationProperties

注册bean:

@Configuration
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
上述列子将会被注册为
<i><code>@Component
@ConfigurationProperties(prefix="acme")
public class AcmeProperties {

	// ... see the preceding example

}</code></i>

这种对于外部配置的使一种很好的方式:代码如下:

# application.yml

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

# additional configuration as required

我们简单的使用即可:如下代码所示:

@Service
public class MyService {

	private final AcmeProperties properties;

	@Autowired
	public MyService(AcmeProperties properties) {
	    this.properties = properties;
	}

 	//...

	@PostConstruct
	public void openConnection() {
		Server server = new Server(this.properties.getRemoteAddress());
		// ...
	}

}
01. 第三方配置
与使用 @ConfigurationProperties 注解类一样,可以使用一个公用的 @Bean

方法,这种方式适用于外部控制的一个组件的属性构造。如下代码

@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
	...
}
02. 释放绑定
Spring Boot 使用了一些释放规则去绑定环境变量到 @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;
	}

}
03. 属性转换

spring boot尝试控制外部属性与其绑定的属性变量类型是一致的。如果要自定义转换,可以提供一个 ConversionService服务去 编辑属性或者通过 @ConfigurationPropertiesBinding 使用去自定义转换器。

04. @configuration验证

对于提供了   @Validated 注解的属性,spring boot总要去验证 @ConfigurationProperties  的合法性。可以通过 JSR-303  javax.validation 去验证器合法性 ,如下代码:

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

	@NotNull
	private InetAddress remoteAddress;

	// ... getters and setters

}

为了能触发验证器,必须要关联其赌赢的@validate,如下代码:

@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

	}

}

可以通过自定义的验证器去验证。

05. @configuarationProperties 与@value

@value是核心的内嵌属性,其不提供安全配置属性。以下是 @ConfigurationProperties  与  @Value 的支持:

特性 @ConfigurationProperties
松绑定 yes no
元数据支持 yes No
SpEL evaluation no yes

备注:以上文档参考 https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#using-boot-devtools-globalsettings

原文  https://yq.aliyun.com/articles/327585
正文到此结束
Loading...