SpringBoot学习篇|Yaml配置文件属性注入
/resources/application.properties
可以配置哪些内容呢?
参考: 官方配置文档
application.properties–>application.yaml
首先可以看一下从哪里知道可以导入yaml的(实际上官方更推荐使用yaml)
我们可以从当前项目的pom.xml
到org.springframework.boot
的.xml配置文件看一下include
标签可见一下内容
语法:
application.properties:
key=value
application.yaml:
key:空格value
可以看到没有空格的时候配置是无效的
yaml的配置示例:
代码语言:javascript复制#对空格的要求很严格.
#最强大在于可以注入到配置类中!!!!
#键值对
name: h0cksr
#对象
person1:
name: h0cksr
age: 18
face:
eyes: 2
mouth: 1
#对象的行内写法
person2: {name: h0cksr,age: 18, face: {eyes: 2,mouth: 1}}
#数组
pets1:
- cat
- dog
- pig
#数组写法二
pets2: [cat,dog,pig]
properties配置示例:
代码语言:javascript复制#相比之下单调得多,只有一种语法
name=h0cksr
person.name=h0cksr
person.age=18
person.face.eyes=2
person.face.mouth=1
使用示例(yaml文件属性注入)
方法一:application.yaml
我们直接将application.properties删除后把上面的yaml示例写入/resources/application.yaml
Person类:
代码语言:javascript复制package com.example.demo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component//注册Bean,只有注册Bean之后才能通过ConfigurationProperties注释导入yaml属性配置
@ConfigurationProperties(prefix = "person1")//将person1对象的属性读取并且赋值给同变量名的成员
public class Person {
private String name;
private Integer age;
private Map<String,Object> face;
public Person(){
}
public Person(String name,Integer age,Map<String,Object> face){
this.name=name;
this.age=age;
this.face=face;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setFace(Map<String, Object> face) {
this.face = face;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Map<String, Object> getFace() {
return face;
}
@Override
public String toString() {
return "Person{"
"name='" name '''
", age=" age
", face=" face
'}';
}
}
重写测试类com.example.demo.Demo3ApplicationTests
代码语言:javascript复制package com.example.demo;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.function.context.test.FunctionalSpringBootTest;
import java.io.IOException;
@SpringBootTest
public class Demo3ApplicationTests {
@Autowired
private Person person;
@Test
void contextLoads() throws IOException {
System.out.println(person);
}
}
运行com.example.demo.Demo3ApplicationTests
可以看到yaml的对象属性值已经赋值到了这个Person类对象属性中
理解:
@Component
和@ConfigurationProperties
注解让Person类被注册为Bean并且将person1的对象属性赋值给当前全部变量
如果Person不是一个Bean的话也会报错
@Autowired
注释会自动调用构造函数,并调用Person类的setter方法将yaml对象的属性赋值给新对象
注:如果缺少属性的setter方法就会导致程序报错,如果yaml文件对象中缺少Person对应的属性的话输出该属性为Null
方法二
可以通过@Value
注解设置指定的默认值
package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class Person {
@Value("hcksr")
private String name;
@Value("18")
private Integer age;
private Map<String,Object> face;
public Person(){
}
public Person(String name,Integer age,Map<String,Object> face){
this.name=name;
this.age=age;
this.face=face;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setFace(Map<String, Object> face) {
this.face = face;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Map<String, Object> getFace() {
return face;
}
@Override
public String toString() {
return "Person{"
"name='" name '''
", age=" age
", face=" face
'}';
}
}
方法三:xxx.yaml
默认情况下是会自动读取application.yaml
和application.properties
配置文件的,但是如果配置文件名不是appincation的时候要怎样将文件配置属性注入到类中呢?
答案是通过使用一个新的注释@PropertySource
导入指定配置文件的属性
这种方法可以导入一个文件的全部属性,但是并不会自动赋值,需要我们自己通过@Value
注解使用SPEL表达式获取属性值,但貌似会有些限制(也可能是我表达式的问题,并不能直接获取一个对象或者一个Map例如face进行赋值)
以下为name和age参数的获取示例:
h0cksr.yaml
代码语言:javascript复制name: {random.uuid}
age:{random.int}
face:
eyes: 22
mouth: 11
person:
name: h0cksr
age: 18
face:
eyes: 2
mouth: 1
代码语言:javascript复制package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
//@PropertySource(value = "classpath:h0cksr.properties")//导入h0cksr.properties和h0cksr.yaml的内容
@PropertySource(value = "classpath:h0cksr.yaml")
public class Person {
@Value("{name}")//默认获取到的是person.name: h0cksr, 使用{person.name}会报错
private String name;
@Value("{age}")//获取到的是person.age: 18,使用{person.age}会报错
private Integer age;
// @Value("{face}") //{face}获取对象赋值失败,和.properties一样不能通过${xxx}获取带有属性的对象
private Map<String,Object> face;
public Person(){
}
public Person(String name,Integer age,Map<String,Object> face){
this.name=name;
this.age=age;
this.face=face;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setFace(Map<String, Object> face) {
this.face = face;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Map<String, Object> getFace() {
return face;
}
@Override
public String toString() {
return "Person{"
"name='" name '''
", age=" age
", face=" face
'}';
}
}
h0cksr.properties
代码语言:javascript复制name={random.uuid}
age={random.int}
face.eyes=22
face.mouth=11
person.name=h0cksr
person.age=18
person.face.eyes=2
person.face.mouth=1
代码语言:javascript复制package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@PropertySource(value = "classpath:h0cksr.properties")//导入h0cksr.properties和h0cksr.yaml的内容
//@PropertySource(value = "classpath:h0cksr.yaml")
public class Person {
@Value("{name}")//默认为{random.uuid},使用{person.name}获得h0cksr
private String name;
@Value("{age}")//默认为{random.int},使用{person.age}获得18
private Integer age;
// @Value("{face}") //不能通过{}获取到一个有属性的对象,只能获取到具体的单一一个属性例如{face.eyes}或{person.face.eyes}
private Map<String,Object> face;
public Person(){
}
public Person(String name,Integer age,Map<String,Object> face){
this.name=name;
this.age=age;
this.face=face;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setFace(Map<String, Object> face) {
this.face = face;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Map<String, Object> getFace() {
return face;
}
@Override
public String toString() {
return "Person{"
"name='" name '''
", age=" age
", face=" face
'}';
}
}
小结
不管是.yaml
还是.properties
都可以写SPEL表达式
另外也可以在@Value
注释写SPEL表达式获取导入的变量属性
${}的SPEL取值类型是有限制的,对于更多类型的取值需要用到其它的SPEL语法,这点在这里就不过多赘述,感兴趣可以参考下面两个链接:
https://www.jianshu.com/p/e0b50053b5d3
http://c.biancheng.net/spring/spel.html
松散绑定
application.yaml
代码语言:javascript复制pe-r-son:
na-me: h0cksr
a-g-e: 18
fa-ce:
eyes: 2
mouth: 1
代码语言:javascript复制package com.example.demo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String name;
private Integer age;
private Map<String,Object> face;
public Person(){
}
public Person(String name,Integer age,Map<String,Object> face){
this.name=name;
this.age=age;
this.face=face;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setFace(Map<String, Object> face) {
this.face = face;
}
public String getName() {
return name;
}
public Integer getAge() {
return age;
}
public Map<String, Object> getFace() {
return face;
}
@Override
public String toString() {
return "Person{"
"name='" name '''
", age=" age
", face=" face
'}';
}
}
这里的Person其实就是上面方法一中的代码,但是运行后可以看到此时application.yaml
中的属性名为pe-r-son
,na-me
,a-g-e
,fa-ce
但是这几个属性却被作为prefix的person
参数读取到并且准确无误地注入到了Person的name
,age
,face
当中,这就是松散绑定的效果了
相比之下,如果使用@Value
获取属性的话那松散绑定就会失效了
JSR303校验
如果对Person类加了@Validated
注释,那么就可以对类的属性进行类型校验,可以通过给属性添加注解检测属性的格式是否为长度,日期,邮箱等格式或其它格式,如果不是则报错,具体使用方法可以参考下面链接
https://www.jianshu.com/p/554533f88370
总结
- 配置yml和配置properties都可以获取到值,强烈推荐yaml
- 如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下@value
- 如果说,我们专门编写了一个JavaBean来和配置文件进行映射,就直接使用configurationProperties,不要犹豫!