使用@Value("${property}")
注解注入配置属性有时会很麻烦,尤其是当您使用多个属性或数据本质上是分层的时。Spring Boot提供了一种使用属性的替代方法,该方法使强类型的Bean可以管理和验证应用程序的配置。
另请参阅
@Value
和类型安全配置属性的区别。
2.7.1 JavaBean属性绑定
可以绑定一个声明标准JavaBean属性的bean,如以下示例所示:
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) { ... }
}
}
前面的POJO(Plain Ordinary Java Object)定义了以下属性:
acme.enabled
,其默认值为false
。acme.remote-address
,其类型可以从String
强制转换。acme.security.username
,带有嵌套的“ security(安全)”对象,其名称由属性名称确定。 特别是,返回类型根本不使用,可能是SecurityProperties
(安全属性)。acme.security.password
,与上面的类似。acme.security.roles
,带有默认为USER
的一个String
类型的集合。
Spring Boot中,映射到
@ConfigurationProperties
类的属性(这些属性是通过属性文件,YAML文件,环境变量等配置的)是公共的API,但是类本身的访问器(getters/setters)并不意味着可以直接使用。
这种安排依赖于默认的空构造函数,并且getter和setter通常是强制性的,因为绑定是通过标准Java Beans属性描述符进行的,就像在Spring MVC中一样。在以下情况中,可以省略setter:
- Maps(映射),只要它们被始化,就只需要使用getter而不需要使用setter,因为它们可以通过绑定器(被绑定字段)来改变。
- 既可以通过索引(通常是YAML),也可以使用单个逗号分隔的值(通常是Properties)来访问集合和数组。在后一种情况下,必须使用setter。我们建议始终为此类类型添加setter。如果初始化集合,请确保它是可变的(如上例所示的是不可变的)。
- 如果嵌套的POJO属性已被初始化(如前面示例中的
Security
字段),则不需要setter方法。如果希望绑定器(被绑定字段)通过使用其默认构造函数动态创建实例,则需要一个setter。有些人使用Lombok项目自动添加setter和getter。确保Lombok不会为这种类型生成任何特定的构造函数,因为容器会自动使用它来实例化该对象。 最后,仅考虑标准Java Bean属性,不支持对静态属性的绑定。
2.7.2 构造函数绑定
上一节中的示例可以以不可变(字段)的方式重写,如下例所示:
package com.example;
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("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
public boolean isEnabled() { ... }
public InetAddress getRemoteAddress() { ... }
public Security getSecurity() { ... }
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() { ... }
public String getPassword() { ... }
public List<String> getRoles() { ... }
}
}
在此设置中,@ConstructorBinding
注解用于指示应使用构造函数绑定。这意味着绑定器(被绑定字段)将期望找到带有您希望绑定的参数的构造函数。@ConstructorBinding
类的嵌套成员(例如,上例中的Security
)也将通过其构造函数进行绑定。
可以使用@DefaultValue
指定默认值,并将应用相同的转换服务将String
值强制转化为缺失属性的目标类型。默认情况下,如果未将任何属性绑定到Security
,则AcmeProperties
实例包含的security
字段将为null
。如果您希望Security
即使没有属性绑定也返回一个非null的实例,则可以使用一个空的@DefaultValue
注解达到这种效果:
package com.example;
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("acme")
public class AcmeProperties {
private final boolean enabled;
private final InetAddress remoteAddress;
private final Security security;
public AcmeProperties(boolean enabled, InetAddress remoteAddress, @DefaultValue Security security) {
this.enabled = enabled;
this.remoteAddress = remoteAddress;
this.security = security;
}
}
要使用构造函数绑定,必须使用
@EnableConfigurationProperties
或配置属性扫描来启用该类。您不能对通过常规Spring机制创建的bean(例如,@Component
bean、通过@Bean
方法创建的bean或使用@Import
加载的bean )使用构造函数绑定。
如果您的类具有多个构造函数,则可以直接在应绑定的构造函数上使用
@ConstructorBinding
。
不建议
java.util.Optional
与@ConfigurationProperties
一起使用,因为它主要用于返回类型。因此,它不太适合配置属性注入。为了与其他类型的属性保持一致,如果确实声明了一个Optional
属性且该属性没有值,则将会绑定成null
,而不是一个空的Optional
。
2.7.3 启用@ConfigurationProperties注释的类型
Spring Boot提供了绑定@ConfigurationProperties
类型并将其注册为Bean的基础架构。您可以逐类启用配置属性,也可以启用与组件扫描类似的方式进行配置属性扫描。
有时,带@ConfigurationProperties
注解的类可能不适合扫描,例如,如果您正在开发自己的自动配置,或者想要有条件地启用它们。在这些情况下,请使用@EnableConfigurationProperties
注解指定要处理的类型列表。可以在任何@Configuration
类上完成此操作,如以下示例所示:
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
要使用配置属性扫描,请将@ConfigurationPropertiesScan
注解添加到您的应用程序。通常,它将添加到带有@SpringBootApplication
注解的主应用程序类中,但也可以将其添加到任何@Configuration
类中。默认情况下,将从声明注释的类所在的包中进行扫描。如果要定义要扫描的特定程序包,可以按照以下示例所示进行操作:
@SpringBootApplication
@ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}
当使用配置属性扫描或通过
@EnableConfigurationProperties
注册@ConfigurationProperties
bean,这个bean有个常规的名称:<prefix>-<fqn>
。其中,<prefix>
是在@ConfigurationProperties
注解中指定的环境键的前缀,<fqn>
是bean的完全限定名。如果@ConfigurationProperties
注解不提供任何前缀,则仅使用bean的完全限定名称。 上例中的bean名称为acme-com.example.AcmeProperties
。
我们建议@ConfigurationProperties
仅用于处理环境,尤其不要从上下文中注入其他bean。对于极端情况,可以使用setter注入,或者使用框架提供的任何*Aware
接口(例如,如果需要访问Environment
,则使用EnvironmentAware
)。如果仍然要使用构造函数注入其他bean,则必须使用@Component
注解此配置属性bean,并使用基于JavaBean的属性绑定。
2.7.4 使用@ConfigurationProperties注解的类型
这种配置样式特别适用于SpringApplication
的外部YAML配置,如下所示:
acme:
remote-address: 192.168.1.1
security:
username: admin
roles:
- USER
- ADMIN
要使用@ConfigurationProperties
bean,可以像使用其他任何bean一样注入它们,如下所示:
@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());
// ...
}
}
使用
@ConfigurationProperties
还可以为您生成元数据文件,IDE可以使用这些元数据文件为自己的键提供自动完成功能。有关详细信息,请参见附录。
2.7.5 第三方配置
@ConfigurationProperties
除了可以用于注解类外,还可以在public的@Bean
方法上使用。当要将属性绑定到控制范围之外的第三方组件时,这样做特别有用。
要从Environment
属性中配置bean ,添加@ConfigurationProperties
到它的bean注册中,如下示例所示:
@ConfigurationProperties(prefix = "another")
@Bean
public AnotherComponent anotherComponent() {
...
}
用another
前缀定义的所有JavaBean属性,都被以类似于前面AcmeProperties
示例的方式,映射到AnotherComponent
bean 。
2.7.6 宽松绑定
Spring Boot使用一些宽松的规则将Environment
属性绑定到@ConfigurationProperties
Bean,因此Environment
属性名称和Bean属性名称之间不需要完全匹配。有用的常见示例包括:破折号分隔的环境属性(例如,context-path
绑定到contextPath
),大写的环境属性(例如,PORT
绑定到port
)。
例如,考虑如下的@ConfigurationProperties
类:
@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;
}
}
前面的代码中,可以使用以下属性名称:
表3.宽松的绑定
属性 | 注意 |
---|---|
acme.my-project.person.first-name |
短横线命名(Kebab case),在.properties 和.yml 文件中,建议使用。 |
acme.myProject.person.firstName |
标准驼峰式语法。 |
acme.my_project.person.first_name |
下划线表示法,在.properties 和.yml 文件中,建议使用的另一种格式。 |
ACME_MYPROJECT_PERSON_FIRSTNAME |
大写格式,在使用系统环境变量时,建议这样使用。 |
![]()
prefix
注解的值必须使用短横线命名(用-
分隔的小写字母,例如acme.my-project.person
)。
表4.每个属性源的宽松绑定规则
属性源 | 单个 | 列表 |
---|---|---|
Properties文件 | 骆驼命名法,短横线命名法,下划线分隔 | 使用[ ] 或以逗号分隔值的标准列表语法 |
YAML文件 | 骆驼命名法,短横线命名法,下划线分隔 | 标准YAML列表语法或以逗号分隔的值 |
环境变量 | 以下划线作为定界符的大写字母格式(请参阅从环境变量绑定)。 | 包围的数字值的下划线界定格式(请参阅环境变量的绑定) |
系统属性 | 骆驼命名法,短横线命名法,下划线分隔 | 使用[ ] 或以逗号分隔值的标准列表语法 |
我们建议,如果可能的话,属性以小写的以短横线间隔的格式存储,例如
my.property-name=acme
。
绑定映射
绑定到Map
属性时,如果key
包含除小写字母数字字符或-
之外的任何内容,则需要使用方括号表示法,以便保留原始值。如果键没有被[]
环绕,所有的除非字母数字或-
以外的字符会被删除。例如,考虑将以下属性绑定到Map
:
Properties:
acme.map.[/key1]=value1
acme.map.[/key2]=value2
acme.map./key3=value3
Yaml:
acme:
map:
"[/key1]": value1
"[/key2]": value2
"/key3": value3
上面的属性绑定到Map
中/key1
,/key2
并key3
的键。
对于YAML文件,方括号需要用引号引起来,以键能被正确解析。
环境变量的绑定
大多数操作系统对可用于环境变量的名称有严格的规则。例如,Linux shell变量只能包含字母(a
到z
、A
到Z
)、数字(0
到9
)或下划线字符(_
)。按照约定,Unix shell变量也将以大写字母命名。
Spring Boot的宽松绑定规则尽可能设计成与这些命名限制相兼容。
要将规范形式的属性名称转换为环境变量名称,可以遵循以下规则:
- 用下划线(
_
)代替点(.
)。 - 删除所有破折号(
-
)。 - 转换成大写。
例如,配置属性spring.main.log-startup-info
是名为SPRING_MAIN_LOGSTARTUPINFO
的环境变量。
绑定到对象列表时也可以使用环境变量。要绑定到List
,元素编号应在变量名称中用下划线包起来。
例如,配置属性my.acme[0].other
将使用名为MY_ACME_0_OTHER
的环境变量。
2.7.7 合并复杂类型
如果在多个位置配置了列表,则通过替换整个列表来进行覆盖。
例如,假定MyPojo
具有name
和description
属性,默认情况下属性值为null
。以下示例暴露了来自AcmeProperties
对象的MyPojo
列表:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final List<MyPojo> list = new ArrayList<>();
public List<MyPojo> getList() {
return this.list;
}
}
考虑以下配置:
Properties:
acme.list[0].name=my name
acme.list[0].description=my description
#---
spring.config.activate.on-profile=dev
acme.list[0].name=my another name
Yaml:
acme:
list:
- name: "my name"
description: "my description"
---
spring:
config:
activate:
on-profile: "dev"
acme:
list:
- name: "my another name"
如果dev
配置未激活,则AcmeProperties.list
包含一个MyPojo
条目,如前面定义的那样。如果启用了dev
配置,则list
仍然仅包含一个条目(name为my another name
,description为null
)。此配置不会在列表中添加第二个MyPojo
实例,并且不会合并项目。
在多个配置中指定了List
时,将使用优先级最高的那个(并且只是该优先级的那个)。考虑以下示例:
Properties:
acme.list[0].name=my name
acme.list[0].description=my description
acme.list[1].name=another name
acme.list[1].description=another description
#---
spring.config.activate.on-profile=dev
acme.list[0].name=my another name
Yaml:
acme:
list:
- name: "my name"
description: "my description"
- name: "another name"
description: "another description"
---
spring:
config:
activate:
on-profile: "dev"
acme:
list:
- name: "my another name"
在前面的示例中,如果dev
配置处于活动状态,则AcmeProperties.list
包含一个 MyPojo
条目(name为my another name
,description为null
)。对于YAML而言,可以使用逗号分隔的列表和YAML列表都可以完全覆盖列表的内容。
对于Map
属性,可以绑定从多个来源的属性值。但是,对于多个源中的同一属性,将使用优先级最高的属性。以下示例暴露了AcmeProperties
中的Map<String, MyPojo>
:
@ConfigurationProperties("acme")
public class AcmeProperties {
private final Map<String, MyPojo> map = new HashMap<>();
public Map<String, MyPojo> getMap() {
return this.map;
}
}
考虑以下配置:
Properties:
acme.map.key1.name=my name 1
acme.map.key1.description=my description 1
#---
spring.config.activate.on-profile=dev
acme.map.key1.name=dev name 1
acme.map.key2.name=dev name 2
acme.map.key2.description=dev description 2
Yaml:
acme:
map:
key1:
name: "my name 1"
description: "my description 1"
---
spring:
config:
activate:
on-profile: "dev"
acme:
map:
key1:
name: "dev name 1"
key2:
name: "dev name 2"
description: "dev description 2"
如果dev
配置未处于活动状态,则AcmeProperties.map
包含一个带有键为key1
的条目(name为my name 1
,description为my description 1
)。如果启用了dev
配置,则map
包含两个带有键为key1
(name为dev name 1
,description为my description 1
)和key2
(name为dev name 2
,description为dev description 2
)的项。
前述合并规则适用于所有属性源中的属性,而不仅适用于文件的。
2.7.8 属性转换
当Spring Boot将外部应用程序属性绑定到@ConfigurationProperties
bean时,它试图强制将外部应用程序属性转换成正确的类型。如果需要自定义类型转换,则可以提供一个ConversionService
bean(具有一个名为conversionService
的Bean)或一个自定义的属性编辑器(通过CustomEditorConfigurer
Bean)、自定义Converters
(具有注解为@ConfigurationPropertiesBinding
的Bean)。
由于在应用程序生命周期中的非常早期就请求了此bean,因此请确保限制
ConversionService
正在使用的依赖项。通常,您需要的任何依赖项可能在创建时未完全初始化。如果配置的key不需要强制且仅依赖具有@ConfigurationPropertiesBinding
限定符的自定义转换器,你可能需要重命名自定义ConversionService
。
持续时间的转换
Spring Boot为表达持续时间提供了专门的支持。如果暴露一个java.time.Duration
类型的属性,在应用程序属性中可以使用以下格式:
- 用常规
long
类型数值的表现形式(使用毫秒作为默认单位,除非指定了@DurationUnit
注解) java.time.Duration
使用的标准ISO-8601格式- 将数值和单位耦合的更易读格式(例如,
10s
表示10秒)
考虑以下示例:
@ConfigurationProperties("app.system")
public class AppSystemProperties {
@DurationUnit(ChronoUnit.SECONDS)
private Duration sessionTimeout = Duration.ofSeconds(30);
private Duration readTimeout = Duration.ofMillis(1000);
public Duration getSessionTimeout() {
return this.sessionTimeout;
}
public void setSessionTimeout(Duration sessionTimeout) {
this.sessionTimeout = sessionTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
public void setReadTimeout(Duration readTimeout) {
this.readTimeout = readTimeout;
}
}
要指定一个会话的超时为30秒,使用30
,PT30S
和30s
都是等效的。一个500毫秒的读取超时,可以的格式包括:500
,PT0.5S
和500ms
。
您还可以使用任何受支持的单位,包括:
ns
,十亿分之一秒us
,微秒ms
,毫秒s
,秒m
,分钟h
,小时d
,天
默认单位是毫秒,可以使用@DurationUnit
覆盖默认值(使用上面的示例中所示的方法)。
如果您更喜欢使用构造函数绑定,则可以暴露这些相同的属性,如以下示例所示:
@ConfigurationProperties("app.system")
@ConstructorBinding
public class AppSystemProperties {
private final Duration sessionTimeout;
private final Duration readTimeout;
public AppSystemProperties(@DurationUnit(ChronoUnit.SECONDS) @DefaultValue("30s") Duration sessionTimeout,
@DefaultValue("1000ms") Duration readTimeout) {
this.sessionTimeout = sessionTimeout;
this.readTimeout = readTimeout;
}
public Duration getSessionTimeout() {
return this.sessionTimeout;
}
public Duration getReadTimeout() {
return this.readTimeout;
}
}
如果要升级一个
Long
类型的时间属性值,如果定义的时间单位不是毫秒的话,请使用@DurationUnit
确保时间的单位。这样做可以提供透明的升级途径,同时支持更丰富的格式。
日期的转换
Spring Boot除了对持续时间的支持外,还可以使用java.time.Period
类型。在应用程序属性中,可以使用以下格式:
- 常规
int
类型的表示形式(除非使用@PeriodUnit注解
指定,否则使用天作为默认单位) java.time.Period
使用的标准ISO-8601格式- 将数值和单位耦合的更简洁格式(例如,
1y3d
表示1年零3天)
这种简洁格式支持以下单位:
y
,年m
,月w
,周d
,天
![]()
java.time.Period
类型从不实际存储星期数,这只是一个表示“ 7天”的快捷方式。
数据大小的转换
Spring框架使用DataSize
类型的值表示字节数。应用程序属性中, 如果要暴露一个DataSize
类型的属性,提供了以下格式:
- 常规的
long
类型的数值的表示形式(除非已经使用@DataSizeUnit
指定,否则使用字节作为默认单位) - 将值和单位耦合的更具可读性的格式(例如,
10MB
意味着10兆字节)
考虑以下示例:
@ConfigurationProperties("app.io")
public class AppIoProperties {
@DataSizeUnit(DataUnit.MEGABYTES)
private DataSize bufferSize = DataSize.ofMegabytes(2);
private DataSize sizeThreshold = DataSize.ofBytes(512);
public DataSize getBufferSize() {
return this.bufferSize;
}
public void setBufferSize(DataSize bufferSize) {
this.bufferSize = bufferSize;
}
public DataSize getSizeThreshold() {
return this.sizeThreshold;
}
public void setSizeThreshold(DataSize sizeThreshold) {
this.sizeThreshold = sizeThreshold;
}
}
指定一个10 兆字节的缓冲区大小,使用10000000
和10MB
是等效的。指定一个256个字节的阈值,可以使用256
或256B
。
您也可以使用任何受支持的单位。它们是:
B
,字节KB
,千字节MB
,兆字节GB
,千兆字节TB
,太字节
默认单位是字节,可以使用@DataSizeUnit
覆盖默认值(如上面的示例中所示的方法)。
如果您更喜欢使用构造函数绑定,则使用如下例所示的方法暴露这些相同的属性:
@ConfigurationProperties("app.io")
@ConstructorBinding
public class AppIoProperties {
private final DataSize bufferSize;
private final DataSize sizeThreshold;
public AppIoProperties(@DataSizeUnit(DataUnit.MEGABYTES) @DefaultValue("2MB") DataSize bufferSize,
@DefaultValue("512B") DataSize sizeThreshold) {
this.bufferSize = bufferSize;
this.sizeThreshold = sizeThreshold;
}
public DataSize getBufferSize() {
return this.bufferSize;
}
public DataSize getSizeThreshold() {
return this.sizeThreshold;
}
}
如果要升级
Long
类型的属性,请使用@DataSizeUnit
确保定义的单位(如果不是字节的话)。这样做可以提供透明的升级途径,同时支持更丰富的格式。
2.7.9 @ConfigurationProperties验证
当使用Spring的@Validated
注解对@ConfigurationProperties
类注释时,Spring Boot就会尝试验证这个类。可以直接在配置类上使用JSR-303 javax.validation
约束注解。为此,请确保在类路径上有兼容的JSR-303实现,然后将约束注解添加到字段中,如下例所示:
@ConfigurationProperties(prefix="acme")
@Validated
public class AcmeProperties {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}
您还可以通过使用注解为
@Bean
方法(此方法使用@Validated
创建配置属性)来触发验证。
为了确保始终为嵌套的属性触发验证,即使未找到任何属性,相关字段也必须使用@Valid
注解。如下例(基于前面的AcmeProperties
示例)所示:
@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
}
}
您还可以通过创建名为configurationPropertiesValidator
的bean定义来添加自定义Spring Validator
。该@Bean
方法应声明成static
类型。在应用程序生命周期中,配置属性验证器创建的是时期是非常早的,并且将@Bean
方法声明为static类型可以在没有实例化@Configuration
类的情况下使得Bean创建。这样做避免了由早期实例化引起的任何问题。
![]()
spring-boot-actuator
模块包括一个暴露所有@ConfigurationProperties
bean的端点。将Web浏览器指向/actuator/configprops
,或使用等效的JMX端点。 有关详细信息,请参见“生产就绪功能”部分。
2.7.10 @ConfigurationProperties与@Value
@Value
注解是核心容器的功能,它不提供作为类型安全配置属性的相同的功能。下表总结了@ConfigurationProperties
和@Value
支持的功能:
特征 | @ConfigurationProperties |
@Value |
---|---|---|
宽松的绑定 | 是 | 受限(请参阅下面的注释) |
元数据支持 | 是 | 否 |
SpEL 评价 |
否 | 是 |
如果您确实想使用
@Value
,我们建议您以规范形式(仅使用小写字母的短横线命名法)引用属性名称。这将使Spring Boot可以使用与@ConfigurationProperties
进行放松绑定的相同逻辑。例如,使用@Value("{demo.item-price}")
,将从application.properties
文件中采集demo.item-price和``demo.itemPrice
格式的声明,也同时会从系统变量中查找DEMO_ITEMPRICE
的定义。如果你使用的@Value("{demo.itemPrice}")
,demo.item-price和``DEMO_ITEMPRICE
将不会予以考虑。
如果您为自己的组件定义了一组配置键,我们建议您将它们组合在以@ConfigurationProperties
标记的POJO中。这样做将为您提供结构化、类型安全的对象,您可以将其注入到自己的bean中。
最后,尽管您可以在@Value
中写入SpEL
表达式,但在应用程序属性文件中不会处理此类表达式。