本文翻译自:http://docs.spring.io/spring-boot/docs/2.0.0.M2/reference/htmlsingle/
详细介绍Spring boot的关键特征,针对有一定springboot基础的同学。
目录
- 1 外部配置
- 1.7 类型安全配置Properties
- 1.7.1 第三方配置
- 1.7.2 轻松绑定
- 1.7.3 属性转换
- 1.7.4 @ConfigurationProperties验证
- 1.7.5 @ConfigurationProperties vs. @Value
- 1.7 类型安全配置Properties
1. 外部配置
1.7 类型安全配置Properties
使用@Value(“$ {property}”)注释来注入配置属性有时可能很麻烦,特别是如果您正在使用多个属性或数据是层次结构的属性。 Spring Boot提供了一种处理属性的替代方法,它允许强类型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("foo")
public class FooProperties {
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定义了以下属性:
- foo.enabled,默认为false
- foo.remote-address,可以强转为String
- foo.security.username强制的类型,其中嵌套的“安全性”的名称由属性名称决定。特别是返回类型并没有被使用,并且可以是SecurityProperties
- foo.security.password
- foo.security.roles,其中包含String
注意:
Getters和setter通常是强制性的,因为绑定是通过标准的Java Beans属性描述符,就像在Spring MVC中一样。在某些情况下可能会忽略一个设置器:
- 只要初始化它们就需要一个getter,但不一定是一个setter,因为它们可以被binder绑定。
- 集合和数组可以通过索引(通常使用YAML)或使用单个逗号分隔值(属性)来访问。在后一种情况下,设置者是强制性的。我们建议您始终为此类型添加一个设置器。如果初始化集合,请确保它不是不可变的(如上例)
- 如果已初始化嵌套POJO属性(如上例中的Security字段),则不需要setter。如果您希望binder使用其默认构造函数即时创建实例,则需要一个setter。
有些人使用Project Lombok自动添加getter和setter。确保Lombok不会为此类型生成任何特定的构造函数因为它将被容器自动使用来实例化对象。
您还需要列出要在@EnableConfigurationProperties注释中注册的属性类:
@Configuration
@EnableConfigurationProperties(FooProperties.class)
public class MyConfiguration {
}
注意:
当@ConfigurationProperties bean以这种方式注册时,该bean将具有常规名称:<prefix>-<fqn>,在@ConfigurationProperties注释中指定的环境密钥前缀<prefix>和bean的完全限定名称<fqn>。如果注释不提供任何前缀,则仅使用该bean的完全限定名称。
上面示例中的bean名称将是foo-com.example.FooProperties。
即使上述配置将为FooProperties创建一个常规bean,我们建议@ConfigurationProperties仅通过Environment处理,特别是不从上下文中注入其他bean。话虽如此,@EnableConfigurationProperties注释也会自动应用于您的项目,以便使用@ConfigurationProperties注释的所有现有bean都将从Environment配置。您可以通过确保FooProperties已经是一个bean来快速上面的MyConfiguration
@Component
@ConfigurationProperties(prefix="foo")
public class FooProperties {
// ... see above
}
这种配置方式与SpringApplication外部YAML配置相当:
# application.yml
foo:
remote-address: 192.168.1.1
security:
username: foo
roles:
- USER
- ADMIN
# additional configuration as required
要使用@ConfigurationProperties bean,您可以像其他任何bean一样注入它们。
@Service
public class MyService {
private final FooProperties properties;
@Autowired
public MyService(FooProperties properties) {
this.properties = properties;
}
//...
@PostConstruct
public void openConnection() {
Server server = new Server(this.properties.getRemoteAddress());
// ...
}
}
使用@ConfigurationProperties还可以生成IDE可以为自己的密钥提供自动完成的元数据文件。
1.7.1 第三方配置
除了使用@ConfigurationProperties来注释类,还可以在public @Bean方法中使用它。当您希望将属性绑定到不受控制的第三方组件时,这可能特别有用。
要从Environment属性配置一个bean,请将@ConfigurationProperties添加到其Bean注册中:
@ConfigurationProperties(prefix = "bar")
@Bean
public BarComponent barComponent() {
...
}
使用bar前缀定义的任何属性将以与上述FooProperties示例类似的方式映射到该BarComponent bean上
1.7.2 轻松绑定
Spring Boot使用一些轻松的规则将Environment属性绑定到@ConfigurationProperties bean,因此不需要在Environment属性名称和bean属性名称之间进行完全匹配。常用的例子是有用的,例如虚线分隔(例如上下文路径绑定到contextPath)和大写(例如PORT绑定到端口)环境属性。例如,给定以下@ConfigurationProperties类:
@ConfigurationProperties(prefix="person")
public class OwnerProperties {
private String firstName;
public String getFirstName() {
return this.firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
}
可以使用以下属性名称:
属性 | 注意 |
---|---|
person.firstName | 标准驼峰语法。 |
person.first-name | 虚拟符号,推荐用于.properties和.yml文件。 |
person.first_name | 下划线符号,用于.properties和.yml文件的替代格式。 |
PERSON_FIRST_NAME | 大写格式。推荐使用系统环境变量时。 |
1.7.3 属性转换
当Spring绑定到@ConfigurationProperties bean时,Spring将尝试将外部应用程序属性强制为正确的类型。如果需要自定义类型转换,您可以提供ConversionService bean(使用bean id conversionService)或自定义属性编辑器(通过CustomEditorConfigurer bean)或自定义转换器(使用注释为@ConfigurationPropertiesBinding的bean定义)。
注意:
由于在应用程序生命周期中早期请求了该bean,因此请确保限制ConversionService正在使用的依赖关系。通常,您需要的任何依赖项可能在创建时可能未完全初始化。如果配置密钥强制不需要,并且仅依赖使用@ConfigurationPropertiesBinding限定的自定义转换器,则可能需要重命名自定义ConversionService。
1.7.4 @ConfigurationProperties验证
Spring引导将尝试使用Spring的@Validated注释来注释@ConfigurationProperties类。您可以直接在配置类上使用JSR-303 javax.validation约束注释。只需确保您的类路径中符合JSR-303的实现,然后在您的字段中添加约束注释:
@ConfigurationProperties(prefix="foo")
@Validated
public class FooProperties {
@NotNull
private InetAddress remoteAddress;
// ... getters and setters
}
为了验证嵌套属性的值,您必须将关联字段注释为@Valid以触发其验证。例如,基于上述FooProperties示例:
@ConfigurationProperties(prefix="connection")
@Validated
public class FooProperties {
@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方法应该声明为静态的。配置属性验证器是在应用程序的生命周期早期创建的,并声明@Bean方法,因为static允许创建bean,而无需实例化@Configuration类。这避免了早期实例化可能引起的任何问题。有一个属性验证样本,所以你可以看到如何设置。
注意:
spring-boot-actuator模块包括一个暴露所有@ConfigurationProperties bean的端点。只需将您的Web浏览器指向/configprops或使用等效的JMX终结点。
1.7.5 @ConfigurationProperties vs. @Value
@Value是核心容器功能,它不提供与类型安全配置属性相同的功能。下表总结了@ConfigurationProperties和@Value支持的功能:
Feature | @ConfigurationProperties | @Value |
---|---|---|
Relaxed binding | Yes | No |
Meta-data support | Yes | No |
SpEL evaluation | No | Yes |
如果您为自己的组件定义了一组配置密钥,我们建议您可以将它们分组到使用@ConfigurationProperties注释的POJO中。还请注意,由于@Value不支持轻松绑定,如果您需要使用环境变量提供该值,那么它不是一个很好的候选人。最后,当您可以在@Value中编写一个SpEL表达式时,这些表达式不会从应用程序属性文件处理。