微信公众号:一个优秀的废人。若有问题,请后台留言,反正我也不会听。前端
最近有跳槽的想法,因此故意复习了下 SpringBoot 的相关知识,复习得比较细。其中有些,我感受是之前忽略掉的东西,好比 @Value 和 @ConfigurationProperties 的区别 。java
定义两个对象,一个学生对象,对应着一个老师对象,代码以下:git
@Component
@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {
private String firstName;
private String lastName;
private Integer age;
private String gender;
private String city;
private Teacher teacher;
private List<String> hobbys;
private Map<String,Integer> scores;
//注意,为了测试必须重写 toString 和 get,set 方法
}
复制代码
public class Teacher {
private String name;
private Integer age;
private String gender;
//注意,为了测试必须重写 toString 和 get,set 方法
}
复制代码
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootValConproDemoApplicationTests {
@Autowired
private Student student;
@Test
public void contextLoads() {
// 这里为了方便,但工做中千万不能用 System.out
System.out.println(student.toString());
}
}
复制代码
Student{firstName='陈', lastName='一个优秀的废人', age=24, gender='男', city='广州', teacher=Teacher{name='eses', age=24, gender='女'}, hobbys=[篮球, 羽毛球, 兵兵球], scores={java=100, Python=99, C=99}}
复制代码
@Value 支持三种取值方式,分别是 字面量、${key}从环境变量、配置文件中获取值以及 #{SpEL}github
@Component
//@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {
/** * <bean class="Student"> * <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * <bean/> */
@Value("陈") // 字面量
private String firstName;
@Value("${student.lastName}") // 从环境变量、配置文件中获取值
private String lastName;
@Value("#{12*2}") // #{SpEL}
private Integer age;
private String gender;
private String city;
private Teacher teacher;
private List<String> hobbys;
private Map<String,Integer> scores;
//注意,为了测试必须重写 toString 和 get,set 方法
}
复制代码
Student{firstName='陈', lastName='一个优秀的废人', age=24, gender='null', city='null', teacher=null, hobbys=null, scores=null}
复制代码
两者区别 | @ConfigurationProperties | @Value |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
从上表能够看见,@ConfigurationProperties 和 @Value 主要有 5 个不一样,其中第一个功能上的不一样,上面已经演示过。下面我来介绍下剩下的 4 个不一样。算法
松散语法的意思就是一个属性在配置文件中能够有多个属性名,举个栗子:学生类当中的 firstName 属性,在配置文件中能够叫 firstName、first-name、first_name 以及 FIRST_NAME。 而 @ConfigurationProperties 是支持这种命名的,@Value 不支持。下面以 firstName 为例,测试一下。以下代码:spring
学生类的 firstName 属性在 yml 文件中被定义为 first_name:数据库
student:
first_name: 陈 # 学生类的 firstName 属性在 yml 文件中被定义为 first_name
lastName: 一个优秀的废人
age: 24
gender: 男
city: 广州
teacher: {name: eses,age: 24,gender: 女}
hobbys: [篮球,羽毛球,兵兵球]
scores: {java: 100,Python: 99,C++: 99}
复制代码
学生类:springboot
@Component
@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {
/** * <bean class="Student"> * <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * <bean/> */
//@Value("陈") // 字面量
private String firstName;
//@Value("${student.lastName}") // 从环境变量、配置文件中获取值
private String lastName;
//@Value("#{12*2}") // #{SpEL}
private Integer age;
private String gender;
private String city;
private Teacher teacher;
private List<String> hobbys;
private Map<String,Integer> scores;
//注意,为了测试必须重写 toString 和 get,set 方法
}
复制代码
测试结果:微信
Student{firstName='陈', lastName='一个优秀的废人', age=24, gender='男', city='广州', teacher=Teacher{name='eses', age=24, gender='女'}, hobbys=[篮球, 羽毛球, 兵兵球], scores={java=100, Python=99, C=99}}
复制代码
学生类:app
@Component
//@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {
/** * <bean class="Student"> * <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * <bean/> */
//@Value("陈") // 字面量
@Value("${student.firstName}")
private String firstName;
//@Value("${student.lastName}") // 从环境变量、配置文件中获取值
private String lastName;
//@Value("#{12*2}") // #{SpEL}
private Integer age;
private String gender;
private String city;
private Teacher teacher;
private List<String> hobbys;
private Map<String,Integer> scores;
//注意,为了测试必须重写 toString 和 get,set 方法
}
复制代码
测试结果:启动报错,找不到 bean。
从上面两个测试结果能够看出,使用 @ConfigurationProperties 注解时,yml 中的属性名为 last_name 而学生类中的属性为 lastName 但依然能取到值,而使用 @value 时,使用 lastName 确报错了。证实 @ConfigurationProperties 支持松散语法,@value 不支持。
SpEL 使用 #{...} 做为定界符 , 全部在大括号中的字符都将被认为是 SpEL , SpEL 为 bean 的属性进行动态赋值提供了便利。
如上述介绍 @Value 注解使用方法时,有这样一段代码:
@Value("#{12*2}") // #{SpEL}
private Integer age;
复制代码
证实 @Value 是支持 SpEL 表达式的。
因为 yml 中的 # 被当成注释看不到效果。因此咱们新建一个 application.properties 文件。把 yml 文件内容注释,咱们在 properties 文件中把 age 属性写成以下所示:
student.age=#{12*2}
复制代码
把学生类中的 @ConfigurationProperties 注释打开,注释 @value 注解。运行报错, age 属性匹配异常。
说明 @ConfigurationProperties 不支持 SpEL
加入 @Length 校验:
@Component
@Validated
//@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {
/** * <bean class="Student"> * <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * <bean/> */
//@Value("陈") // 字面量
@Value("${student.first-name}")
@Length(min=5, max=20, message="用户名长度必须在5-20之间")
private String firstName;
//@Value("${student.lastName}") // 从环境变量、配置文件中获取值
private String lastName;
//@Value("#{12*2}") // #{SpEL}
private Integer age;
private String gender;
private String city;
private Teacher teacher;
private List<String> hobbys;
private Map<String,Integer> scores;
}
复制代码
yaml:
student:
first_name: 陈
复制代码
测试结果:
Student{firstName='陈', lastName='null', age=null, gender='null', city='null', teacher=null, hobbys=null, scores=null}
复制代码
yaml 中的 firstname 长度为 1 。而检验规则规定 5-20 依然能取到属性,说明检验不生效,@Value 不支持 JSR303 数据校验
学生类:
@Component
@Validated
@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {
/** * <bean class="Student"> * <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * <bean/> */
//@Value("陈") // 字面量
//@Value("${student.first-name}")
@Length(min=5, max=20, message="用户名长度必须在5-20之间")
private String firstName;
//@Value("${student.lastName}") // 从环境变量、配置文件中获取值
private String lastName;
//@Value("#{12*2}") // #{SpEL}
private Integer age;
private String gender;
private String city;
private Teacher teacher;
private List<String> hobbys;
private Map<String,Integer> scores;
}
复制代码
测试结果:报错
[firstName],20,5]; default message [用户名长度必须在5-20之间]
复制代码
校验生效,支持 JSR303 数据校验。
复杂类型封装指的是,在对象以及 map (如学生类中的老师类以及 scores map)等属性中,用 @Value 取是取不到值,好比:
@Component
//@Validated
//@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {
/** * <bean class="Student"> * <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * <bean/> */
//@Value("陈") // 字面量
//@Value("${student.first-name}")
//@Length(min=5, max=20, message="用户名长度必须在5-20之间")
private String firstName;
//@Value("${student.lastName}") // 从环境变量、配置文件中获取值
private String lastName;
//@Value("#{12*2}") // #{SpEL}
private Integer age;
private String gender;
private String city;
@Value("${student.teacher}")
private Teacher teacher;
private List<String> hobbys;
@Value("${student.scores}")
private Map<String,Integer> scores;
}
复制代码
这样取是报错的。而上文介绍 @ConfigurationProperties 和 @Value 的使用方法时已经证明 @ConfigurationProperties 是支持复杂类型封装的。也就是说 yaml 中直接定义 teacher 以及 scores 。 @ConfigurationProperties 依然能取到值。
若是说,只是在某个业务逻辑中须要获取一下配置文件中的某项值,使用 @Value;好比,假设如今学生类加多一个属性叫 school 那这个属性对于该校全部学生来讲都是同样的,但防止我这套系统到了别的学校就用不了了。那咱们能够直接在 yml 中给定 school 属性,用 @Value 获取。固然上述只是举个粗暴的例子,实际开发时,school 属性应该是保存在数据库中的。
若是说,专门编写了一个 javaBean 来和配置文件进行映射,咱们就直接使用 @ConfigurationProperties。
若是以为对你有帮助,请给个 Star 再走呗,很是感谢。
若是本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写做的动力。
另外,关注以后在发送 1024 可领取免费学习资料。
资料详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享