声明
这个系列文章是翻译自https://www.baeldung.com/的系列博客,个人感觉是一个非常不错的Spring Boot 教程。原网站属于一个公司,主要开展有偿培训业务,但提供相关文字教程的免费阅读和下载。因为我并没有在网页找到相关版权描述信息,所以并不能确定是否可以自由翻译和转载,如果有版权问题,请联系我,我会撤下这个系列文章。
原文地址:
因为版权的关系,本文禁止转载。
概述
本教程将展示如何通过Java配置和 @PropertySource. 在Spring中设置和使用属性
我们还将看到属性如何在Spring Boot 中工作。
通过注释注册属性文件
Spring 3.1还引入了新的 @PropertySource 注释,作为将属性源添加到环境中的方便机制。
我们可以将此注释与 @Configuration 注释结合使用:
"classpath:foo.properties")
(public class PropertiesWithJavaConfig {
//...
}
注册新属性文件的另一个非常有用的方法是使用占位符,它允许我们在运行时动态地选择正确的文件:
({ "classpath:persistence-${envTarget:mysql}.properties"
})
...
定义多个属性位置
@PropertySource 注释根据Java 8约定是可重复的。因此,如果我们使用的是Java 8或更高版本,我们可以使用这个注释来定义多个属性位置:
"classpath:foo.properties")
("classpath:bar.properties")
(public class PropertiesWithJavaConfig {
//...
}
当然,我们也可以使用 @PropertySources 注释并指定 @PropertySource 数组。这适用于任何支持的Java版本,而不仅仅是Java 8或更高版本:
({ "classpath:foo.properties"),
( "classpath:bar.properties")
(})
public class PropertiesWithJavaConfig {
//...
}
无论是哪种情况,都值得注意的是,在属性名冲突的情况下,最后一次源读取优先。
使用/注入属性
注入一个带有的属性很简单:
"${jdbc.url}" )
( private String jdbcUrl;
我们还可以为属性指定默认值:
"${jdbc.url:aDefaultUrl}" )
( private String jdbcUrl;
Spring 3.1中添加的新 PropertySourcesPlaceholderConfigurer 解析bean定义属性值和@Value注释中的${...}占位符。
最后,我们可以使用 Environment API获取属性的值:
private Environment env;
...
dataSource.setUrl(env.getProperty("jdbc.url"));
使用 Spring Boot 属性
在我们进入属性的更高级配置选项之前,让我们花一些时间来看看Spring Boot 中的新属性支持。
一般来说,与标准Spring相比,这种新的支持涉及的配置更少,这当然是Boot 的主要目标之一。
application.properties:默认属性文件
Boot 将其典型的约定优于配置方法应用于属性文件。这意味着我们可以简单地将 application.properties 文件放在src/main/resources 目录中,它将被自动检测。然后我们可以像往常一样从它注入任何加载的属性。
因此,通过使用这个默认文件,我们不必显式注册 PropertySource,甚至不必提供属性文件的路径。
如果需要,我们还可以在运行时配置不同的文件,使用环境属性:
java -jar app.jar --spring.config.location=classpath:/another-location.properties
从Spring Boot 2.3开始,我们还可以为配置文件指定通配符位置(location)。
例如,我们可以将 spring.config.location 属性设置为config/*/
:
java -jar app.jar --spring.config.location=config/*/
这样,Spring Boot 将在jar文件之外寻找与config/*/
目录模式匹配的配置文件。当我们有多个配置属性源时,这就派上用场了。
从2.4.0版本开始,Spring Boot 支持使用多文档属性文件,类似于YAML的设计:
baeldung.customProperty=defaultValue
#---
baeldung.customProperty=overriddenValue
注意,对于属性文件,三个破折号符号前面有一个注释字符( # )。
环境特定属性文件
如果我们需要针对不同的环境,Boot 中有一个内置的机制。
我们可以简单地在src/main/resources目录中定义一个application-environment.properties文件,然后使用相同的环境名称(environment name)设置Spring配置(profile)。
例如,如果我们定义了一个“staging”环境,这意味着我们必须定义一个staging配置文件,然后定义application-staging. properties。
将加载此env文件,并优先于默认属性文件。请注意,默认文件仍然会被加载,只是当存在属性冲突时,环境特定的属性文件优先。
测试特定属性文件
我们可能还需要在测试应用程序时使用不同的属性值。
Spring Boot 通过在测试运行期间查看我们的 src/test/resources 目录来处理这个问题。同样,默认属性仍然可以正常注入,但如果发生冲突,这些属性将被覆盖。
@TestPropertySource 注解
如果我们需要对测试属性进行更细粒度的控制,那么我们可以使用 注解。
这允许我们为特定的测试上下文设置测试属性,优先于默认的属性源:
SpringRunner.class)
("/foo.properties")
(public class FilePropertyInjectionUnitTest {
"${foo}")
( private String foo;
public void whenFilePropertyProvided_thenProperlyInjected() {
assertThat(foo).isEqualTo("bar");
}
}
如果我们不想使用文件,我们可以直接指定名称和值:
SpringRunner.class)
(properties = {"foo=bar"})
(public class PropertyInjectionUnitTest {
"${foo}")
( private String foo;
public void whenPropertyProvided_thenProperlyInjected() {
assertThat(foo).isEqualTo("bar");
}
}
我们也可以使用 @SpringBootTest 注解 的properties参数实现类似的效果:
SpringRunner.class)
(
( properties = {"foo=bar"}, classes = SpringBootPropertiesTestApplication.class)
public class SpringBootPropertyInjectionIntegrationTest {
"${foo}")
( private String foo;
public void whenSpringBootPropertyProvided_thenProperlyInjected() {
assertThat(foo).isEqualTo("bar");
}
}
分层属性
如果我们有分组在一起的属性,我们可以使用 注释,它将把这些属性层次结构映射到Java对象图中。
让我们使用一些用于配置数据库连接的属性:
database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
然后让我们使用注释将它们映射到数据库对象:
prefix = "database")
(public class Database {
String url;
String username;
String password;
// standard getters and setters
}
Spring Boot 再次将其约定应用于配置方法,自动在属性名称及其对应的字段之间进行映射。我们需要提供的只是属性前缀。
如果您想深入了解配置属性,请查看。
备选方案:YAML文件
Spring还支持YAML文件。
所有相同的命名规则都适用于特定于测试、特定于环境和默认属性文件。唯一的区别是文件扩展名和对类路径上的SnakeYAML库的依赖。
YAML特别适合分层属性存储;以下属性文件:
database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
secret: foo
与以下YAML文件同义:
database
url jdbc postgresql /localhost 5432/instance
username foo
password bar
secret foo
值得一提的是,YAML文件不支持 @PropertySource 注释,所以如果我们需要使用这个注释,它会限制我们使用属性文件。
另一个值得注意的地方是,在2.4.0版本中,Spring Boot 改变了从多文档YAML文件加载属性的方式。以前,它们的添加顺序基于配置文件激活顺序。但是,在新版本中,框架遵循我们前面为.properties文件指出的相同排序规则;在文件中声明在较低位置的属性将简单地覆盖较高位置的属性。
此外,在这个版本中,配置文件不能再从特定于配置文件的文档中激活,使结果更清晰,更可预测。
导入其他配置文件
在2.4.0版本之前,Spring Boot 允许使用 spring.config.location 和 spring.config.additional-location 属性包含其他配置文件,但它们有一定的限制。例如,它们必须在启动应用程序之前定义(作为环境或系统属性,或使用命令行参数),因为它们在过程的早期使用。
在上述版本中,我们可以使用 application.properties 或 application.yml 文件中的 spring.config.import 属性来轻松包含其他文件。此属性支持一些有趣的功能:
-
添加多个文件或目录
-
可以从类路径或外部目录加载文件
-
指示如果未找到文件或文件是可选文件,启动过程是否应失败
-
导入无扩展名文件
让我们看一个有效的例子:
spring.config.import=classpath:additional-application.properties,
classpath:additional-application[.yml],
optional:file:./external.properties,
classpath:additional-application-properties/
注意:这里我们使用换行符来格式化这个属性,只是为了清楚起见。
Spring将把 import 视为直接插入到import声明下面的新文档。
命令行参数的属性
除了使用文件,我们还可以直接在命令行上传递属性:
java -jar app.jar --property="value"
我们也可以通过系统属性来实现这一点,这些属性在-jar命令之前而不是之后提供:
java -Dproperty.name="value" -jar app.jar
环境变量的属性
Spring boot 还将检测环境变量,将其视为属性:
export name=value
java -jar app.jar
属性值的随机化
如果我们不想要决定论属性值,我们可以使用 来随机化属性值:
random.number=${random.int}
random.long=${random.long}
random.uuid=${random.uuid}
其他类型的属性源
Spring Boot 支持多种属性源,实现了深思熟虑的排序以允许明智的重写。参考是值得的,它超出了本文的范围。
PropertySourcesPlaceholderConfigurer
除了在Spring中获取属性的方便方法外,我们还可以手动定义和注册属性配置bean。
使用PropertySourcesPlaceholderConfigurer可以让我们完全控制配置,但缺点是更冗长,而且大多数时候都是不必要的。
让我们看看如何使用Java配置定义这个bean:
public static PropertySourcesPlaceholderConfigurer properties(){
PropertySourcesPlaceholderConfigurer pspc
= new PropertySourcesPlaceholderConfigurer();
Resource[] resources = new ClassPathResource[ ]
{ new ClassPathResource( "foo.properties" ) };
pspc.setLocations( resources );
pspc.setIgnoreUnresolvablePlaceholders( true );
return pspc;
}
父子上下文中的属性
这个问题反复出现:当我们的Web应用程序有一个父上下文和一个子上下文时会发生什么?父上下文可能有一些公共的核心功能和bean,然后是一个(或多个)子上下文,可能包含特定于servlet的bean。
在这种情况下,定义属性文件并将其包含在这些上下文中的最佳方法是什么?如何从Spring中最好地检索这些属性?
我们将给予一个简单的分解。
如果文件是在父上下文中定义的:
-
@Value 适用于Child上下文:是的
-
@Value 在父上下文中工作:是的
-
在Child上下文中的environment.getProperty:是的
-
environment.getProperty在父上下文中:是的
如果文件是在“子”上下文中定义的:
-
@Value 适用于Child上下文:是的
-
@Value 在父上下文中工作:否
-
在Child上下文中的environment.getProperty:是的
-
environment.getProperty在父上下文中:否
结论
本文展示了在Spring中使用属性和属性文件的几个示例。
和往常一样,支持本文的整个代码都可以
文章评论