1.为什么要使用yaml给对象属性赋值
- yaml可以直接给实体类的属性赋值
- 原来我们学习的给实体类赋值的方式有两种:①调用有参构造 ②使用注解@value
- 上面两种方式都可以实现对对象成员属性的赋值,但是我们每new一个新对象我们就需要在调用构造的地方显式的传入数据或使用注解@value的地方修改源代码,这显然不是我们想要的
- yaml可以实现在配置文件中配置对象属性
2.实践
- 创建两个pojo:dog+person
package com.thhh.pojo; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @Component public class Dog { @Value("旺财") private String name; @Value("3") private Integer age; public Dog() { } public Dog(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
注意:上面我并没有使用偷懒工具lombok,主要还是回忆一下pojo手动怎么写package com.thhh.pojo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Date; import java.util.List; import java.util.Map; @Component public class Person { private String name; private Integer age; private boolean happy; private Date birth; private Map<String,Object> map; private List<Object> list; @Autowired private Dog dog; public Person() { } public Person(String name, Integer age, boolean happy, Date birth, Map<String, Object> map, List<Object> list, Dog dog) { this.name = name; this.age = age; this.happy = happy; this.birth = birth; this.map = map; this.list = list; this.dog = dog; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public boolean isHappy() { return happy; } public void setHappy(boolean happy) { this.happy = happy; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public Map<String, Object> getMap() { return map; } public void setMap(Map<String, Object> map) { this.map = map; } public List<Object> getList() { return list; } public void setList(List<Object> list) { this.list = list; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", happy=" + happy + ", birth=" + birth + ", map=" + map + ", list=" + list + ", dog=" + dog + '}'; } }
- 测试是否赋值成功
package com.thhh; import com.thhh.pojo.Dog; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class Springboot02ConfigApplicationTests { @Autowired private Dog dog; @Test void contextLoads() { System.out.println(dog); } }
-
上面的测试中我们使用的是@value给属性赋值,当我们需要修改属性值的时候是需要修改源代码的,为了解决这个问题我们采用yaml对对象属性进行赋值
person: name: 张三 age: 18 happy: true birth: 2020/02/02 map: {k1: v1,k2: v2} #map集合按照一个对象来处理,k为成员属性,v为属性值 dog: name: 旺财 age: 3 list: #list按照数组来处理 - code - music - girl
-
在需要注入属性值的类上面添加注解@ConfigurationProperties(prefix = “ymal中对象属性的名称”)
-
但是使用这个注解的时候IDEA会爆红
-
测试对象属性是否注入成功
package com.thhh; import com.thhh.pojo.Dog; import com.thhh.pojo.Person; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; @SpringBootTest class Springboot02ConfigApplicationTests { @Autowired private Person person; @Test void contextLoads() { System.out.println(person); } }
-
注意:在ymal中写属性的时候,我故意将属性dog和属性list的顺序进行了颠倒,但是结果还是赋值成功,这说明ymal对象属性的自动注入与编写顺序无关,它是按照属性名称进行的匹配,我们可以将yaml中person对象的属性名称进行修改,使得和pojo中属性名称不一致,最终结果你会发现属性名称不一致的成员属性赋值失败,它的值为其对应数据类型的默认值
-
@ConfigurationProperties作用:
- 将配置文件中配置的每一个属性的值,映射到这个组件中;
- 告诉springBoot将本类中的所有属性和配置文件中相关的配置进行绑定
- 参数 prefix = "person”:将配置文件中的person下面的所有属性==——对应==
- 只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能
3.扩展
-
在实际开发的时候我们可以选用yaml和properties两种方式,上面我们使用了yaml,使用properties的时候我们需要使用注解@PropertySource(“properties文件路径”),然后在对应的属性上面使用spring的EL表达式${properties文件中的key}就可以实现属性的赋值;但是这样做步骤就多一些,使用配置文件的好处也仅限于修改属性值的时候不会动源码,来赋值操作都和直接使用@value进行的步骤相同;使用的时候需要设置IDEA配置文件的字符编码
-
yaml除了直接配置属性值之外,它还可以使用一些spring的EL表达式,在这些表达式中我们可以做很多的操作
- 使用表达式作为属性值
- 使用默认值作为属性值
person: name: ${random.uuid} #使用表达式 age: ${random.int} #使用表达式 happy: true birth: 2020/02/02 map: {k1: v1,k2: v2} #map集合按照一个对象来处理,k为成员属性,v为属性值 dog: name: ${person.hello:hello}_旺财 #使用默认值 age: 3 list: #list按照数组来处理 - code - music - girl
- 上面的 ${random.uuid}就可以随机生成一个uuid作为name的值
- ${person.hello:hello}_旺财,这个就更加厉害,首先我们使用 ${person.hello}去取person对象属性的hello的值,如果这个值不存在那么就会使用":"后面的值 " hello"和后面的 "_旺财"进行拼接
- 如果person对象属性中有hello属性
- 上面的功能可以在配置文件中实现,我们的代码就可以减轻响应的工作量,这就是yaml的强大之处,也是springBoot官方推荐使用它的原因
- 对比使用yaml和properties
- cp只需要写一次即可,value则需要每个字段都添加
- 松散绑定:这个什么意思呢?比如我的yml中写的last-name,这个和lastName是一样的,-后面跟着的字母默认是大写的,这就是松散绑定(就是属性字段使用驼峰命名,yaml文件中使用"-"将名称中单词隔开就行,可以直接都使用小写,这样属性值也是可以实现注入的)
- JSR303数据校验,这个就是我们可以在字段是增加一层过滤器验证,可以保证数据的合法性
- 复杂类型封装,yml中可以封装对象,使用@value就不支持
结论
- 配置yml和配置properties都可以获取到值,强烈推荐yml
- 如果我们在某个业务中,只需要获取配置文件中的某个值,可以使用一下@value
- 如果说,我们专门编写了一个JavaBean来和配置文件进行映射,就直接使用@configurationProperties,不要犹豫!