1. Overview
1.概述
This tutorial will show how to set up and use properties in Spring via Java configuration and @PropertySource.
本教程将展示如何通过Java配置和@PropertySource在Spring中设置和使用属性。
We’ll also see how properties work in Spring Boot.
我们还将看到属性在Spring Boot中如何工作。
2. Register a Properties File via Annotations
2.通过注解注册一个属性文件
Spring 3.1 also introduces the new @PropertySource annotation as a convenient mechanism for adding property sources to the environment.
Spring 3.1还引入了新的@PropertySource注解作为向环境添加属性源的便捷机制。
We can use this annotation in conjunction with the @Configuration annotation:
我们可以将这个注解与@Configuration注解一起使用。
@Configuration
@PropertySource("classpath:foo.properties")
public class PropertiesWithJavaConfig {
//...
}
Another very useful way to register a new properties file is using a placeholder, which allows us to dynamically select the right file at runtime:
另一种非常有用的注册新属性文件的方法是使用占位符,这使我们能够在运行时动态地选择正确的文件。
@PropertySource({
"classpath:persistence-${envTarget:mysql}.properties"
})
...
2.1. Defining Multiple Property Locations
2.1.定义多个属性位置
The @PropertySource annotation is repeatable according to Java 8 conventions. Therefore, if we’re using Java 8 or higher, we can use this annotation to define multiple property locations:
@PropertySource 注解是可重复的根据Java 8惯例。因此,如果我们使用Java 8或更高版本,我们可以使用这个注解来定义多个属性位置。
@PropertySource("classpath:foo.properties")
@PropertySource("classpath:bar.properties")
public class PropertiesWithJavaConfig {
//...
}
Of course, we can also use the @PropertySources annotation and specify an array of @PropertySource. This works in any supported Java version, not just in Java 8 or higher:
当然,我们也可以使用@PropertySources注解,并指定一个@PropertySource数组。这在任何支持的Java版本中都适用,而不仅仅是在Java 8或更高版本中。
@PropertySources({
@PropertySource("classpath:foo.properties"),
@PropertySource("classpath:bar.properties")
})
public class PropertiesWithJavaConfig {
//...
}
In either case, it’s worth noting that in the event of a property name collision, the last source read takes precedence.
在这两种情况下,值得注意的是,如果出现属性名称的碰撞,最后读到的源头会优先考虑。
3. Using/Injecting Properties
3.使用/注射的特性
Injecting a property with the @Value annotation is straightforward:
用@Value注解注入一个属性是直接的。
@Value( "${jdbc.url}" )
private String jdbcUrl;
We can also specify a default value for the property:
我们还可以为属性指定一个默认值:。
@Value( "${jdbc.url:aDefaultUrl}" )
private String jdbcUrl;
The new PropertySourcesPlaceholderConfigurer added in Spring 3.1 resolve ${…} placeholders within bean definition property values and @Value annotations.
Spring 3.1中新增的PropertySourcesPlaceholderConfigurer 在Bean定义的属性值和@Value注释中解决${…}占位符。
Finally, we can obtain the value of a property using the Environment API:
最后,我们可以使用Environment API获得一个属性的值。
@Autowired
private Environment env;
...
dataSource.setUrl(env.getProperty("jdbc.url"));
4. Properties With Spring Boot
4.使用Spring Boot的属性
Before we go into more advanced configuration options for properties, let’s spend some time looking at the new properties support in Spring Boot.
在我们进入更高级的属性配置选项之前,让我们花些时间看看Spring Boot中新的属性支持。
Generally speaking, this new support involves less configuration compared to standard Spring, which is of course one of the main goals of Boot.
一般来说,与标准Spring相比,这种新的支持涉及的配置更少,这当然是Boot的主要目标之一。
4.1. application.properties: the Default Property File
4.1.application.properties:默认属性文件
Boot applies its typical convention over configuration approach to property files. This means that we can simply put an application.properties file in our src/main/resources directory, and it will be auto-detected. We can then inject any loaded properties from it as normal.
Boot对属性文件采用了其典型的约定俗成的配置方法。这意味着我们可以简单地在src/main/resources目录下放置一个application.properties文件,它将被自动检测到。然后我们可以像平常一样从它那里注入任何加载的属性。
So, by using this default file, we don’t have to explicitly register a PropertySource or even provide a path to a property file.
因此,通过使用这个默认文件,我们不必明确地注册一个PropertySource,甚至不必提供一个属性文件的路径。
We can also configure a different file at runtime if we need to, using an environment property:
如果需要的话,我们也可以在运行时使用环境属性配置一个不同的文件。
java -jar app.jar --spring.config.location=classpath:/another-location.properties
As of Spring Boot 2.3, we can also specify wildcard locations for configuration files.
从Spring Boot 2.3开始,我们还可以为配置文件指定通配符位置。
For example, we can set the spring.config.location property to config/*/:
例如,我们可以将spring.config.location属性设为config/*/。
java -jar app.jar --spring.config.location=config/*/
This way, Spring Boot will look for configuration files matching the config/*/ directory pattern outside of our jar file. This comes in handy when we have multiple sources of configuration properties.
这样,Spring Boot将在我们的jar文件之外寻找与config/*/目录模式相匹配的配置文件。当我们有多个配置属性的来源时,这就很方便了。
Since version 2.4.0, Spring Boot supports using multi-document properties files, similarly as YAML does by design:
自2.4.0版本起,Spring Boot支持使用多文档属性文件,类似于YAML的设计。
baeldung.customProperty=defaultValue
#---
baeldung.customProperty=overriddenValue
Note that for properties files, the three-dashes notation is preceded by a comment character (#).
请注意,对于属性文件,三横线符号前面有一个注释字符(#)。
4.2. Environment-Specific Properties File
4.2.特定环境的属性文件
If we need to target different environments, there’s a built-in mechanism for that in Boot.
如果我们需要针对不同的环境,Boot里有一个内置的机制。
We can simply define an application-environment.properties file in the src/main/resources directory, and then set a Spring profile with the same environment name.
我们可以简单地在src/main/resources目录下定义一个application-environment.properties文件,然后以相同的环境名称设置一个Spring配置文件。
For example, if we define a “staging” environment, that means we’ll have to define a staging profile and then application-staging.properties.
例如,如果我们定义一个 “staging “环境,这意味着我们必须定义一个staging配置文件,然后application-staging.properties。
This env file will be loaded and will take precedence over the default property file. Note that the default file will still be loaded, it’s just that when there is a property collision, the environment-specific property file takes precedence.
这个env文件将被加载,并且将优先于默认的属性文件。注意,默认文件仍将被加载,只是当有属性碰撞时,环境特定的属性文件将优先。
4.3. Test-Specific Properties File
4.3.测试专用的属性文件
We might also have a requirement to use different property values when our application is under test.
当我们的应用程序处于测试状态时,我们也可能有要求使用不同的属性值。
Spring Boot handles this for us by looking in our src/test/resources directory during a test run. Again, default properties will still be injectable as normal but will be overridden by these if there is a collision.
Spring Boot通过在测试运行期间查看src/test/resources目录来为我们处理这个问题。同样,默认的属性仍然可以正常注入,但如果发生碰撞,将被这些属性所覆盖。
4.4. The @TestPropertySource Annotation
4.4.@TestPropertySource 注释
If we need more granular control over test properties, then we can use the @TestPropertySource annotation.
如果我们需要对测试属性进行更精细的控制,那么我们可以使用@TestPropertySource注解。
This allows us to set test properties for a specific test context, taking precedence over the default property sources:
这允许我们为特定的测试环境设置测试属性,优先于默认属性源:。
@RunWith(SpringRunner.class)
@TestPropertySource("/foo.properties")
public class FilePropertyInjectionUnitTest {
@Value("${foo}")
private String foo;
@Test
public void whenFilePropertyProvided_thenProperlyInjected() {
assertThat(foo).isEqualTo("bar");
}
}
If we don’t want to use a file, we can specify names and values directly:
如果我们不想使用一个文件,我们可以直接指定名称和值。
@RunWith(SpringRunner.class)
@TestPropertySource(properties = {"foo=bar"})
public class PropertyInjectionUnitTest {
@Value("${foo}")
private String foo;
@Test
public void whenPropertyProvided_thenProperlyInjected() {
assertThat(foo).isEqualTo("bar");
}
}
We can also achieve a similar effect using the properties argument of the @SpringBootTest annotation:
我们也可以使用properties 参数来实现类似的效果,@SpringBootTest注解:。
@RunWith(SpringRunner.class)
@SpringBootTest(
properties = {"foo=bar"}, classes = SpringBootPropertiesTestApplication.class)
public class SpringBootPropertyInjectionIntegrationTest {
@Value("${foo}")
private String foo;
@Test
public void whenSpringBootPropertyProvided_thenProperlyInjected() {
assertThat(foo).isEqualTo("bar");
}
}
4.5. Hierarchical Properties
4.5.分层属性
If we have properties that are grouped together, we can make use of the @ConfigurationProperties annotation, which will map these property hierarchies into Java objects graphs.
如果我们有分组的属性,我们可以利用@ConfigurationProperties注解,它将把这些属性层次映射成Java对象图。
Let’s take some properties used to configure a database connection:
让我们来看看用于配置数据库连接的一些属性。
database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
And then let’s use the annotation to map them to a database object:
然后让我们使用注释将它们映射到数据库对象中。
@ConfigurationProperties(prefix = "database")
public class Database {
String url;
String username;
String password;
// standard getters and setters
}
Spring Boot applies it’s convention over configuration approach again, automatically mapping between property names and their corresponding fields. All that we need to supply is the property prefix.
Spring Boot再次应用其约定俗成的配置方法,自动在属性名和其相应字段之间进行映射。我们所需要提供的只是属性前缀。
If you want to dig deeper into configuration properties, have a look at our in-depth article.
如果你想深入了解配置属性,请看我们的深度文章。
4.6. Alternative: YAML Files
4.6.替代方案 YAML文件
Spring also supports YAML files.
Spring也支持YAML文件。
All the same naming rules apply for test-specific, environment-specific, and default property files. The only difference is the file extension and a dependency on the SnakeYAML library being on our classpath.
所有相同的命名规则适用于测试专用、环境专用和默认属性文件。唯一的区别是文件的扩展名和对SnakeYAML库的依赖性在我们的classpath上。
YAML is particularly good for hierarchical property storage; the following property file:
YAML特别适合于分层的属性存储;下面的属性文件。
database.url=jdbc:postgresql:/localhost:5432/instance
database.username=foo
database.password=bar
secret: foo
is synonymous with the following YAML file:
是以下YAML文件的同义词。
database:
url: jdbc:postgresql:/localhost:5432/instance
username: foo
password: bar
secret: foo
It’s also worth mentioning that YAML files do not support the @PropertySource annotation, so if we need to use this annotation, it would constrain us to using a properties file.
还值得一提的是,YAML文件不支持@PropertySource注解,所以如果我们需要使用这个注解,就会限制我们使用属性文件。
Another remarkable point is that in version 2.4.0 Spring Boot changed the way in which properties are loaded from multi-document YAML files. Previously, the order in which they were added was based on the profile activation order. With the new version, however, the framework follows the same ordering rules that we indicated earlier for .properties files; properties declared lower in the file will simply override those higher up.
另一个值得注意的地方是,在2.4.0版本中,Spring Boot改变了从多文档YAML文件加载属性的方式。以前,它们被添加的顺序是基于配置文件的激活顺序。然而,在新版本中,框架遵循了我们之前为.properties文件指出的相同的排序规则;文件中较低位置声明的属性将简单地覆盖较高位置的属性。
Additionally, in this version profiles can no longer be activated from profile-specific documents, making the outcome clearer and more predictable.
此外,在这个版本中,配置文件不再能从特定的配置文件文件中激活,使结果更清晰、更可预测。
4.7. Importing Additional Configuration Files
4.7.导入其他配置文件
Prior to version 2.4.0, Spring Boot allowed including additional configuration files using the spring.config.location and spring.config.additional-location properties, but they had certain limitations. For instance, they had to be defined before starting the application (as environment or system properties, or using command-line arguments) as they were used early in the process.
在2.4.0版本之前,Spring Boot允许使用spring.config.location和spring.config.extra-location属性包括额外的配置文件,但它们有一定的限制。例如,它们必须在启动应用程序之前定义(作为环境或系统属性,或使用命令行参数),因为它们是在流程的早期使用的。
In the mentioned version, we can use the spring.config.import property within the application.properties or application.yml file to easily include additional files. This property supports some interesting features:
在提到的版本中,我们可以在application.properties 或application.yml 文件中使用spring.config.import属性,以轻松包含其他文件。该属性支持一些有趣的功能。
- adding several files or directories
- the files can be loaded either from the classpath or from an external directory
- indicating if the startup process should fail if a file is not found, or if it’s an optional file
- importing extensionless files
Let’s see a valid example:
让我们看看一个有效的例子。
spring.config.import=classpath:additional-application.properties,
classpath:additional-application[.yml],
optional:file:./external.properties,
classpath:additional-application-properties/
Note: here we formatted this property using line breaks just for clarity.
注意:在这里,为了清晰起见,我们使用了换行符来格式化这个属性。
Spring will treat imports as a new document inserted immediately below the import declaration.
Spring将把导入作为一个新的文件插入到紧接着导入声明的下面。
4.8. Properties From Command Line Arguments
4.8.来自命令行参数的属性
Besides using files, we can pass properties directly on the command line:
除了使用文件,我们还可以直接在命令行上传递属性。
java -jar app.jar --property="value"
We can also do this via system properties, which are provided before the -jar command rather than after it:
我们也可以通过系统属性来做到这一点,这些属性是在-jar命令之前而不是之后提供的。
java -Dproperty.name="value" -jar app.jar
4.9. Properties From Environment Variables
4.9.来自环境变量的属性
Spring Boot will also detect environment variables, treating them as properties:
Spring Boot也会检测环境变量,把它们当作属性。
export name=value
java -jar app.jar
4.10. Randomization of Property Values
4.10.财产价值的随机化
If we don’t want determinist property values, we can use RandomValuePropertySource to randomize the values of properties:
如果我们不想要确定性的属性值,我们可以使用RandomValuePropertySource来随机化属性的值。
random.number=${random.int}
random.long=${random.long}
random.uuid=${random.uuid}
4.11. Additional Types of Property Sources
4.11.其他类型的财产来源
Spring Boot supports a multitude of property sources, implementing a well-thought-out ordering to allow sensible overriding. It’s worth consulting the official documentation, which goes further than the scope of this article.
Spring Boot支持众多的属性源,实现了深思熟虑的排序,以允许合理的重写。值得参考的是官方文档,它比本文的范围更深入。
5. Configuration Using Raw Beans — the PropertySourcesPlaceholderConfigurer
5.使用Raw Beans进行配置 – PropertySourcesPlaceholderConfigurer
Besides the convenient methods of getting properties into Spring, we can also define and regiter the property configuration bean manually.
除了用方便的方法将属性引入Spring之外,我们还可以手动定义和注册属性配置Bean。
Working with the PropertySourcesPlaceholderConfigurer gives us full control over the configuration, with the downside of being more verbose and most of the time, unnecessary.
使用PropertySourcesPlaceholderConfigurer可以让我们完全控制配置,但缺点是比较啰嗦,而且大多数时候是不必要的。
Let’s see how we can define this bean using Java configuration:
让我们看看如何使用Java配置来定义这个Bean。
@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;
}
6. Properties in Parent-Child Contexts
6.父子关系中的属性
This question comes up again and again: What happens when our web application has a parent and a child context? The parent context may have some common core functionality and beans, and then one (or multiple) child contexts, maybe containing servlet-specific beans.
这个问题一次又一次地出现了。如果我们的网络应用有一个父级和一个子级上下文,会发生什么?父级上下文可能有一些共同的核心功能和Bean,然后是一个(或多个)子级上下文,可能包含服务专用Bean。
In that case, what’s the best way to define properties files and include them in these contexts? And how to best retrieve these properties from Spring?
在这种情况下,定义属性文件并将其包含在这些上下文中的最佳方法是什么?以及如何从Spring中最好地检索这些属性?
We’ll give a simple breakdown.
我们将给出一个简单的分类。
If the file is defined in the Parent context:
如果该文件是在父类环境中定义的。
- @Value works in Child context: YES
- @Value works in Parent context: YES
- environment.getProperty in Child context: YES
- environment.getProperty in Parent context: YES
If the file is defined in the Child context:
如果该文件是在儿童环境中定义的。
- @Value works in Child context: YES
- @Value works in Parent context: NO
- environment.getProperty in Child context: YES
- environment.getProperty in Parent context: NO
7. Conclusion
7.结论
This article showed several examples of working with properties and properties files in Spring.
这篇文章展示了在Spring中使用属性和属性文件的几个例子。
As always, the entire code backing the article is available over on GitHub.
像往常一样,支持该文章的整个代码可在GitHub上获得。