配置引用
@ConfigurationProperties
Spring Boot 通过 ConfigurationProperties 注解从配置文件中获取属性,可以通过设置 prefix 指定需要批量导入的数据。支持获取字面值,集合,Map,对象等复杂数据。ConfigurationProperties 注解的优缺点如下:
- 可以从配置文件中批量注入属性;
- 支持获取复杂的数据类型;
- 对属性名匹配的要求较低,比如 user-name,user_name,userName,USER_NAME 都可以取值;
- 支持 Java 的 JSR303 数据校验;
- 缺点是不支持强大的 SpEL 表达式;
Properties
/**
* 用户信息
* @ConfigurationProperties : 被修饰类中的所有属性会和配置文件中的指定值(该值通过prefix找到)进行绑定
*/
@Component
@ConfigurationProperties(prefix = "userInfo")
public class UserInfo {
private String account;
private Integer age;
private Boolean active;
private Date createdDate;
private Map<String, Object> map;
private List<Object> list;
private Position position;
// 省略getter,setter,toString方法
}
配置文件占位符
在 application.properties 中的各个参数之间,我们也可以直接通过使用 PlaceHolder 的方式来进行引用,就像下面的设置:
book.name=SpringCloud
book.author=Test
book.desc=${book.author} is writing《${book.name}》
在一些特殊情况下,有些参数我们希望它每次加载的时候不是一个固定的值,比如:密钥、服务端口等。在 Spring Boot 的属性配置文件中,我们可以通过使用 ${random}配置来产生随机的 int 值、long 值或者 string 字符串,这样我们就可以容易的通过配置来属性的随机生成,而不是在程序中通过编码来实现这些逻辑。
ran: # 这里的prefix不能是random,
ran-value: ${random.value}
ran-int: ${random.int}
ran-long: ${random.long}
ran-int-num: ${random.int(10)}
ran-int-range: ${random.int[10,20]}
ran-placeholder: placeholder_${ran.ran-value:此处不能有空格,且key为完整路径}
其对应的 Java 代码类似于:
/**
* 随机数和占位符语法类
*/
@Component
@ConfigurationProperties(prefix = "ran")
public class RandomEntity {
private String ranValue; // 随机生成一个字符串
private Integer ranInt; // 随机生成一个整数
private Long ranLong; // 随机生成一个长整数
private Integer ranIntNum; // 在指定范围内随机生成一个整数
private Integer ranIntRange; // 在指定区间内随机生成一个整数
private String ranPlaceholder; // 占位符
// 省略getter,setter,toString方法e
}
属性校验
@ConfigurationProperties 使用 JSR-303 格式提供属性验证。这允许各种各样的事情,例如,让 hostName 属性成为强制性的:
@NotBlank
private String hostName;
@Length(max = 4, min = 1)
private String authMethod;
@Min(1025)
@Max(65536)
private int port;
@Pattern(regexp = "^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,6}$")
private String from;
@Value
Value 注解的优缺点与 @ConfigurationProperties 正好相反,它只能一个个配置注入值;不支持数组、集合等复杂的数据类型;不支持数据校验;对属性名匹配有严格的要求。最大的特点是支持 SpEL 表达式,使其拥有更丰富的功能。@Value 的使用方式,对于如下的 YAML 定义文件:
wx:
nick-name: wx
email: aa@aa
iphone: 1234567890
abilities: [java, sql, html]
created_date: 2010/03/31 15:27:30
其对应的 Java 类使用如下:
/**
* Value 注解语法类
* 第一步:在属性上添加注解Value注入参数
* 第二步:把Value注解修饰的类添加到Spring的IOC容器中;
* 第三步:添加数据校验注解,检查是否支持数据校验;
*
* 注意点:
* 一、nickName 和 createdDate 在 yml 配置文件中,对应参数分别是中划线和下划线,用于测试其对属性名匹配的松散性
* 二、email和iphone 测试其支持JSR303数据校验
* 三、abilities 测试其支持复杂的数据结构
*
* 结论:
* 一、createDate取值必须和yml配置文件中的参数保持一致,
* 二、既是在iphone上添加邮箱验证注解依然可以通过测试,
* 三、不支持复杂的数据结构,提示错误和第一条相同:IllegalArgumentException: Could not resolve placeholder 'wx.abilities' in value "${wx.abilities}"
*/
@Component
@Validated
public class ValueEntity {
@Value("${wx.nick-name}")
private String nickName;
@Value("${wx.email}")
private String email;
@Email
@Value("${wx.iphone}") // 解析成功,并不支持数据校验
private String iphone;
// @Value("${wx.abilities}") // 解析错误,并不支持复杂的数据结构
private List<String> abilities;
// @Value("${wx.ceatredDate}") // 解析错误,并不支持松散匹配属性,必须严格一致
private Date createdDate;
// Value注解的强大一面:支持SpEL表达式
@Value("#{(1+2-3)/4*5}") // 算术运算
private String operator;
@Value("#{1>2 || 2 <= 3}") // 关系运算
private Boolean comparison;
@Value("#{systemProperties['java.version']}") // 系统配置:os.name
private String systemProperties;
@Value("#{T(java.lang.Math).abs(-18)}") // 表达式
private String mapExpression;
// 省略getter,setter,toString方法
}
@PropertySource
@PropertySource 注解,用于代替 <context:property-placeholader/>
配置,加载 properties 配置文件。有时候我们需要去加载非默认的 profile 文件中的属性,此时就可以用 @PropertySource 将配置文件加载到上下文中,并且通过 @Value 进行注入:
@PropertySource("classpath:foo.properties")
@PropertySource("classpath:bar.properties")
public class PropertiesWithJavaConfig {
//...
}
@PropertySources({
@PropertySource("classpath:foo.properties"),
@PropertySource("classpath:bar.properties")
})
public class PropertiesWithJavaConfig {
//...
}
@Value( "${jdbc.url}" )
private String jdbcUrl;
@Value( "${jdbc.url:aDefaultUrl}" )
private String jdbcUrl;
Binder
在 Spring Boot 2.0 中增加了新的绑定 API 来帮助我们更容易的获取配置信息。假设在 propertes 配置中有这样一个配置:wx.foo=bar
。我们为它创建对应的配置类:
@Data
@ConfigurationProperties(prefix = "wx")
public class FooProperties {
private String foo;
}
接下来,通过最新的 Binder 就可以这样来拿配置信息了:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(Application.class, args);
Binder binder = Binder.get(context.getEnvironment());
// 绑定简单配置
FooProperties foo = binder
.bind("wx", Bindable.of(FooProperties.class))
.get();
System.out.println(foo.getFoo());
}
}
对于复杂的 List 类型:
wx.post[0]=Why Spring Boot
wx.post[1]=Why Spring Cloud
wx.posts[0].title=Why Spring Boot
wx.posts[0].content=It is perfect!
wx.posts[1].title=Why Spring Cloud
wx.posts[1].content=It is perfect too!
要获取这些配置依然很简单,可以这样实现:
ApplicationContext context = SpringApplication.run(Application.class, args);
Binder binder = Binder.get(context.getEnvironment());
// 绑定List配置
List<String> post = binder.bind("wx.post", Bindable.listOf(String.class)).get();
System.out.println(post);
List<PostInfo> posts = binder.bind("wx.posts", Bindable.listOf(PostInfo.class)).get();
System.out.println(posts);