springCore完整学习教程2,入门级别
上集说到:2. 3,咱们从2.3集开始
2. Externalized Configuration
2.3. External Application Properties
Spring Boot会自动找到并加载应用程序。属性和应用程序。当应用程序启动时,从以下位置获取Yaml文件:
从类路径
类路径root
类路径/配置包
从当前目录
使用当前目录
当前目录下的config/子目录
config/子目录的直接子目录
该列表按优先级排序(较低项的值覆盖较早项的值)。加载文件中的文档作为propertresources添加到Spring环境中。
如果您不喜欢application作为配置文件名,您可以通过指定spring.config.name环境属性来切换到另一个文件名。例如,查找我的项目。属性和myproject。你可以这样运行你的应用程序:
2.3.1. Optional Locations
默认情况下,当指定的配置数据位置不存在时,Spring Boot将抛出ConfigDataLocationNotFoundException,并且您的应用程序将不会启动。
如果您想指定一个位置,但不介意它不总是存在,则可以使用可选的:前缀。您可以将此前缀与spring.config.location和spring.config一起使用。附加位置属性,以及spring.config.import声明。
例如,spring.config.import的值为optional:file:./myconfig。属性允许您的应用程序启动,即使myconfig。属性文件丢失。
如果你想忽略所有的configdatalocationnotfoundexception并始终继续启动你的应用程序,你可以使用spring.config。on-not-found财产。使用SpringApplication.setDefaultProperties(…)或使用系统/环境变量将值设置为忽略。
2.3.2. Wildcard Locations
使用通配符
例如,如果你有一些Redis配置和一些MySQL配置,你可能希望将这两部分配置分开,同时要求这两部分都存在于应用程序中。属性文件。这可能导致两个独立的应用程序。属性文件挂载在不同的位置,如/config/redis/application。Properties和/config/mysql/application.properties。在这种情况下,使用通配符位置config/*/将导致两个文件都被处理。
默认情况下,Spring Boot在默认搜索位置中包含config/*/。这意味着将搜索jar之外的/config目录的所有子目录。
通配符位置必须只包含一个*并以*/结尾,如果搜索位置是目录,或者如果搜索位置是文件,则必须包含*/<filename>。带有通配符的位置根据文件名的绝对路径按字母顺序排序。
通配符位置仅适用于外部目录。不能在类路径:location中使用通配符。
2.3.3. Profile Specific Files
就是application-{profile}.yml等 的类型
特定于配置文件的属性是从与标准应用程序相同的位置加载的。属性,特定于配置文件的文件总是覆盖非特定的文件。如果指定了多个配置文件,则应用最后获胜策略。例如,如果profile prod、live是由spring.profiles.active属性指定的,那么application-prod中的值就会被替换。属性可以被application-live.properties中的属性覆盖。
spring.profiles.active=prod
2.3.4. Importing Additional Data
应用程序属性可以使用spring.config.import属性从其他位置导入配置数据。当发现导入时,将对其进行处理,并将其视为插入声明导入的文档下面的附加文档。
例如,在您的类路径应用程序中可能有以下内容。属性文件:
spring.application.name=myapp
spring.config.import=optional:file:./dev.properties
这将触发在当前目录中导入dev.properties文件(如果存在这样的文件)。导入的dev.properties中的值将优先于触发导入的文件。在上面的例子中,dev.properties可以将spring.application.name重新定义为一个不同的值。
这里我举个例子吧
application-prod.yml文件:
server:
port: 3344
spring:
config:
import: classpath:/config/dev.properties
application:
name: myapp
dev.properties
spring.applicdation.name=bb
package com.example.demo.demos;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class Test {
@Value("${spring.application.name}")
public String name;
@GetMapping("/get")
public String getName(){
return name;
}
}
发现生成的是:
这个例子很明显吧!!!(明显还不关注我)
2.3.5. Importing Extensionless Files
某些云平台无法为卷挂载的文件添加文件扩展名。要导入这些无扩展文件,需要给Spring Boot一个提示,以便它知道如何加载它们。您可以通过在方括号中添加扩展提示来实现这一点。
比如:
spring.config.import=file:/etc/config/myconfig[.yaml]
2.3.6. Using Configuration Trees
在云平台(如Kubernetes)上运行应用程序时,通常需要读取平台提供的配置值。出于这种目的使用环境变量并不罕见,但这可能有缺点,特别是在值应该保密的情况下。
2.3.7. Property Placeholders
应用中的值。属性和应用程序。yaml在使用时将通过现有环境进行过滤,因此您可以引用以前定义的值(例如,从系统属性或环境变量)。标准的${name}属性占位符语法可以在值中的任何地方使用。属性占位符还可以使用:指定默认值,以将默认值与属性名称分开,例如${name:default}。
以下示例显示了带默认值和不带默认值的占位符的使用:
app.name=MyApp
app.description=${app.name} is a Spring Boot application written by ${username:Unknown}
假如用户名属性没有在其他地方设置,app.description将具有MyApp是由Unknown编写的Spring Boot应用程序的值。
2.3.8. Working With Multi-Document Files
Spring Boot允许您将单个物理文件拆分为多个逻辑文档,每个文档都是独立添加的。文档按照从上到下的顺序进行处理。以后的文档可以覆盖以前文档中定义的属性。
为应用程序。yaml文件,则使用标准的yaml多文档语法。三个连续的连字符表示一个文档的结束和下一个文档的开始。
例如,下面的文件有两个逻辑文档:
spring:
application:
name: "MyApp"
---
spring:
application:
name: "MyCloudApp"
config:
activate:
on-cloud-platform: "kubernetes"
like this:
spring.application.name=MyApp
#---
spring.application.name=MyCloudApp
spring.config.activate.on-cloud-platform=kubernetes
两个物理文件,但是有三个逻辑项目
2.3.9. Activation Properties
有时,只有在满足某些条件时才激活给定的一组属性是有用的。例如,您可能拥有仅在特定概要文件处于活动状态时才相关的属性。
您可以使用spring.config.activate.*有条件地激活属性文档。
以下激活属性可用:
Property | Note |
---|---|
| A profile expression that must match for the document to be active. |
| The |
例如,下面的命令指定第二个文档仅在Kubernetes上运行时才激活,并且仅当“prod”或“staging”配置文件处于激活状态时才激活:
myprop=always-set
#---
spring.config.activate.on-cloud-platform=kubernetes
spring.config.activate.on-profile=prod | staging
myotherprop=sometimes-set
2.4. Encrypting Properties
Spring Boot没有为加密属性值提供任何内置支持,但是,它提供了修改Spring环境中包含的值所必需的钩子点。
2.5. Working With YAML
YAML是JSON的超集,因此是指定分层配置数据的方便格式。只要在你的类路径上有SnakeYAML库,SpringApplication类就会自动支持YAML作为属性的替代。
2.5.1. Mapping YAML to Properties
YAML文档需要从层次结构格式转换为可与Spring环境一起使用的平面结构。例如,考虑以下YAML文档:
environments:
dev:
url: "https://dev.example.com"
name: "Developer Setup"
prod:
url: "https://another.example.com"
name: "My Cool App"
为了从环境中访问这些属性,它们将被扁平化如下:
environments.dev.url=https://dev.example.com
environments.dev.name=Developer Setup
environments.prod.url=https://another.example.com
environments.prod.name=My Cool App
2.5.2. Directly Loading YAML
Spring Framework提供了两个方便的类,可用于加载YAML文档。YamlPropertiesFactoryBean将YAML作为属性加载,而YamlMapFactoryBean将YAML作为Map加载。
你也可以使用YamlPropertySourceLoader类,如果你想加载YAML作为一个Spring PropertySource。
2.6. Configuring Random Values
RandomValuePropertySource对于注入随机值很有用(例如,在秘密或测试用例中)。它可以生成整数、长整数、uuid或字符串,示例如下:
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]}
我都测试过了,各位当真不点关注?0.0
2.7. Configuring System Environment Properties
Spring Boot支持为环境属性设置前缀。如果系统环境由具有不同配置需求的多个Spring Boot应用程序共享,这将非常有用。系统环境属性的前缀可以直接在SpringApplication上设置。
例如,如果将前缀设置为input,则远程。超时也将在系统环境中解析为input.remote.timeout。
2.8. Type-safe Configuration Properties
使用@Value("${property}")注释注入配置属性有时会很麻烦,特别是在处理多个属性或数据本质上是分层的情况下。Spring Boot提供了另一种处理属性的方法,让强类型bean管理和验证应用程序的配置。
2.8.1. JavaBean Properties Binding
可以绑定声明标准JavaBean属性的bean,如下例所示:
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("my.service")
public class MyProperties {
private boolean enabled;
private InetAddress remoteAddress;
private final Security security = new Security();
public boolean isEnabled() {
return this.enabled;
}
public void setEnabled(boolean enabled) {
this.enabled = enabled;
}
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public void setRemoteAddress(InetAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
private String username;
private String password;
private List<String> roles = new ArrayList<>(Collections.singleton("USER"));
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return this.password;
}
public void setPassword(String password) {
this.password = password;
}
public List<String> getRoles() {
return this.roles;
}
public void setRoles(List<String> roles) {
this.roles = roles;
}
}
}
-
my.service.enabled
, with a value offalse
by default. -
my.service.remote-address
, with a type that can be coerced fromString
. -
my.service.security.username
, with a nested "security" object whose name is determined by the name of the property. In particular, the type is not used at all there and could have beenSecurityProperties
. -
my.service.security.password
. -
my.service.security.roles
, with a collection ofString
that defaults toUSER
.
配置一下主类
@ConfigurationPropertiesScan(basePackages = "com.example.demo.demos")
在配置文件上写:
my.service.enabled=true
my.service.remoteAddress=127.0.0.1
my.service.security.username=admin
my.service.security.password=admin123
my.service.security.roles=USER,ADMIN
就可以测试了,自己测试吧,又不关注我,凭什么给你们测试,哼
2.8.2. Constructor Binding
上一节的例子可以用不可变的方式重写,如下面的例子所示:
import java.net.InetAddress;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.ConstructorBinding;
import org.springframework.boot.context.properties.bind.DefaultValue;
@ConstructorBinding
@ConfigurationProperties("my.service")
public class MyProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public MyProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() {
return this.enabled;
}
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
private final String username;
private final String password;
private final List<String> roles;
public Security(String username, String password, @DefaultValue("USER") List<String> roles) {
this.username = username;
this.password = password;
this.roles = roles;
}
public String getUsername() {
return this.username;
}
public String getPassword() {
return this.password;
}
public List<String> getRoles() {
return this.roles;
}
}
}
在这个设置中,@ConstructorBinding注释用于指示应该使用构造函数绑定。这意味着绑定器将期望找到一个构造函数,其中包含您希望绑定的参数。如果使用的是Java 16或更高版本,则可以对记录使用构造函数绑定。在这种情况下,除非您的记录有多个构造函数,否则不需要使用@ConstructorBinding。
@ConstructorBinding类的嵌套成员(如上面示例中的Security)也将通过它们的构造函数绑定。
默认值可以使用@DefaultValue on来指定
2.8.3. Enabling @ConfigurationProperties-annotated Types
Spring Boot提供了绑定@ConfigurationProperties类型并将它们注册为bean的基础设施。您既可以逐个类地启用配置属性,也可以启用与组件扫描类似的配置属性扫描。
有时,带有@ConfigurationProperties注释的类可能不适合扫描,例如,如果您正在开发自己的自动配置,或者希望有条件地启用它们。在这些情况下,使用@ enablecconfigurationproperties注释指定要处理的类型列表。
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Configuration;
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(SomeProperties.class)
public class MyConfiguration {
}
和
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("some.properties")
public class SomeProperties {
}
要使用配置属性扫描,请在应用程序中添加@ConfigurationPropertiesScan注释。通常,它被添加到带有@SpringBootApplication注释的主应用程序类中,但它也可以添加到任何@Configuration类中。默认情况下,将从声明注释的类的包进行扫描。如果您想定义要扫描的特定包,可以这样做,如下所示:
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.ConfigurationPropertiesScan;
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "com.example.another" })
public class MyApplication {
}
2.8.6. Relaxed Binding
Spring Boot使用一些宽松的规则将Environment属性绑定到@ConfigurationProperties bean,因此在Environment属性名和bean属性名之间不需要精确匹配。这很有用的常见示例包括用虚线分隔的环境属性(例如,上下文路径绑定到contextPath)和大写的环境属性(例如,PORT绑定到PORT)。
例如,考虑下面的@ConfigurationProperties类:
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix = "my.main-project.person")
public class MyPersonProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
使用上述代码,可以使用以下属性名称:
Property | Note |
---|---|
| Kebab case, which is recommended for use in |
| Standard camel case syntax. |
| Underscore notation, which is an alternative format for use in |
| Upper case format, which is recommended when using system environment variables. |
注释的前缀值必须是kebab case(小写并用-分隔,如my.main-project.person),上面使用了驼峰命名法。
2.8.7. Merging Complex Types
当列表在多个位置配置时,重写通过替换整个列表来工作。
例如,假设MyPojo对象的名称和描述属性默认为空。下面的例子展示了MyProperties中的MyPojo对象列表:
import java.util.ArrayList;
import java.util.List;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("my")
public class MyProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
考虑以下配置:
my.list[0].name=my name
my.list[0].description=my description
#---
spring.config.activate.on-profile=dev
my.list[0].name=my another name
2.8.8. Properties Conversion
当Spring Boot绑定到@ConfigurationProperties bean时,它尝试将外部应用程序属性强制为正确的类型。如果您需要自定义类型转换,您可以提供ConversionService bean(带有名为ConversionService的bean)或自定义属性编辑器(通过CustomEditorConfigurer bean)或自定义转换器(带有注释为@ConfigurationPropertiesBinding的bean定义)。
2.8.9. @ConfigurationProperties Validation
每当@ConfigurationProperties类被Spring的@Validated注释时,Spring Boot都会尝试验证它们。您可以使用JSR-303 javax。直接在配置类上验证约束注释。要做到这一点,请确保在你的类路径上有一个兼容的JSR-303实现,然后向你的字段添加约束注释,如下例所示:
import java.net.InetAddress;
import javax.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
@ConfigurationProperties("my.service")
@Validated
public class MyProperties {
@NotNull
private InetAddress remoteAddress;
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public void setRemoteAddress(InetAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
}
您还可以通过用@Validated注释创建配置属性的@Bean方法来触发验证。
为了确保总是触发对嵌套属性的验证,即使没有找到任何属性,也必须用@Valid注释关联字段。下面的示例建立在前面的MyProperties示例之上:
import java.net.InetAddress;
import javax.validation.Valid;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.validation.annotation.Validated;
@ConfigurationProperties("my.service")
@Validated
public class MyProperties {
@NotNull
private InetAddress remoteAddress;
@Valid
private final Security security = new Security();
public InetAddress getRemoteAddress() {
return this.remoteAddress;
}
public void setRemoteAddress(InetAddress remoteAddress) {
this.remoteAddress = remoteAddress;
}
public Security getSecurity() {
return this.security;
}
public static class Security {
@NotEmpty
private String username;
public String getUsername() {
return this.username;
}
public void setUsername(String username) {
this.username = username;
}
}
}
您还可以通过创建一个名为configurationPropertiesValidator的bean定义来添加自定义Spring Validator。@Bean方法应该声明为静态的。配置属性验证器是在应用程序生命周期的早期创建的,并且将@Bean方法声明为静态可以在不实例化@Configuration类的情况下创建bean。这样做可以避免可能由早期实例化引起的任何问题。
2.8.10. @ConfigurationProperties vs. @Value
@Value注释是容器的核心特性,它不提供与类型安全配置属性相同的特性。下表总结了@ConfigurationProperties和@Value支持的特性:
Feature | @ConfigurationProperties | @Value |
---|---|---|
Yes | Limited (see note below) | |
Yes | No | |
| No | Yes |
如果您确实想使用@Value,我们建议您使用规范形式(仅使用小写字母的kebab-case)引用属性名。这将允许Spring Boot使用与放松绑定@ConfigurationProperties时相同的逻辑。
例如,@Value("${demo.item-price}")将选择demo。项目价格和演示。itemPrice表单。属性文件,以及系统环境中的DEMO_ITEMPRICE。如果你使用了@Value("${demo. itemprice}"), demo. itemprice将会被替换。item-price和DEMO_ITEMPRICE将不被考虑。
如果您为自己的组件定义了一组配置键,我们建议您将它们分组在带有@ConfigurationProperties注解的POJO中。这样做将为您提供结构化的、类型安全的对象,您可以将其注入到自己的bean中。
在解析这些文件和填充环境时,不会处理来自应用程序属性文件的SpEL表达式。但是,可以在@Value中编写斯佩尔表达式。如果应用程序属性文件中的属性值是一个SpEL表达式,则在通过@Value使用时对其进行计算。