微信公众号:一个优秀的废人。如有问题,请后台留言,反正我也不会听。

前言

最近有跳槽的想法,所以故意复习了下 SpringBoot 的相关知识,复习得比较细。其中有些,我感觉是以前忽略掉的东西,比如 @Value 和 @ConfigurationProperties 的区别 。

如何使用

定义两个对象,一个学生对象,对应着一个老师对象,代码如下:

  • @ConfigurationProperties
  1. 学生类
@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 方法
}
  1. 老师类
public class Teacher {

    private String name;

    private Integer age;

    private String gender;

    //注意,为了测试必须重写 toString 和 get,set 方法
}
  1. 测试类
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootValConproDemoApplicationTests { @Autowired
private Student student; @Test
public void contextLoads() {
// 这里为了方便,但工作中千万不能用 System.out
System.out.println(student.toString());
}
}
  1. 输出结果
Student{firstName='陈', lastName='一个优秀的废人', age=24, gender='男', city='广州', teacher=Teacher{name='eses', age=24, gender='女'}, hobbys=[篮球, 羽毛球, 兵兵球], scores={java=100, Python=99, C=99}}
  • @Value

@Value 支持三种取值方式,分别是 字面量、${key}从环境变量、配置文件中获取值以及 #{SpEL}

  1. 学生类
@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 方法
}
  1. 测试结果
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 为例,测试一下。如下代码:

  • @ConfigurationProperties

学生类的 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}

学生类:

@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}}
  • @Value

学生类:

@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 , SpEL 为 bean 的属性进行动态赋值提供了便利。

  • @Value

如上述介绍 @Value 注解使用方法时,有这样一段代码:

@Value("#{12*2}") // #{SpEL}
private Integer age;

证明 @Value 是支持 SpEL 表达式的。

  • @ConfigurationProperties

由于 yml 中的 # 被当成注释看不到效果。所以我们新建一个 application.properties 文件。把 yml 文件内容注释,我们在 properties 文件中把 age 属性写成如下所示:

student.age=#{12*2}

把学生类中的 @ConfigurationProperties 注释打开,注释 @value 注解。运行报错, age 属性匹配异常。

说明 @ConfigurationProperties 不支持 SpEL

JSR303 数据校验

  • @Value

加入 @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 数据校验

  • @ConfigurationProperties

学生类:

@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。

完整代码

https://github.com/turoDog/Demo/tree/master/springboot_val_conpro_demo

如果觉得对你有帮助,请给个 Star 再走呗,非常感谢。

后语

如果看到这里,喜欢这篇文章的话,请转发、点赞。微信搜索「一个优秀的废人」,欢迎关注。

回复「1024」送你一套完整的 java、python、c++、go、前端、linux、算法、大数据、人工智能、小程序以及英语教程。

回复「电子书」送你 50+ 本 java 电子书。

Spring Boot2 系列教程(十九) | @Value 和 @ConfigurationProperties 的区别的更多相关文章

  1. Spring Boot2 系列教程(十九)Spring Boot 整合 JdbcTemplate

    在 Java 领域,数据持久化有几个常见的方案,有 Spring 自带的 JdbcTemplate .有 MyBatis,还有 JPA,在这些方案中,最简单的就是 Spring 自带的 JdbcTem ...

  2. Spring Boot2 系列教程(十)Spring Boot 整合 Freemarker

    今天来聊聊 Spring Boot 整合 Freemarker. Freemarker 简介 这是一个相当老牌的开源的免费的模版引擎.通过 Freemarker 模版,我们可以将数据渲染成 HTML ...

  3. Spring Boot2 系列教程 (十八) | 整合 MongoDB

    微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 如题,今天介绍下 SpringBoot 是如何整合 MongoDB 的. MongoDB 简介 MongoDB 是由 C++ ...

  4. Spring Boot2 系列教程 (十四) | 统一异常处理

    如题,今天介绍 SpringBoot 是如何统一处理全局异常的.SpringBoot 中的全局异常处理主要起作用的两个注解是 @ControllerAdvice 和 @ExceptionHandler ...

  5. Spring Boot2 系列教程 (十二) | 整合 thymeleaf

    前言 如题,今天介绍 Thymeleaf ,并整合 Thymeleaf 开发一个简陋版的学生信息管理系统. SpringBoot 提供了大量模板引擎,包含 Freemarker.Groovy.Thym ...

  6. Spring Boot2 系列教程 (十) | 实现声明式事务

    前言 如题,今天介绍 SpringBoot 的 声明式事务. Spring 的事务机制 所有的数据访问技术都有事务处理机制,这些技术提供了 API 用于开启事务.提交事务来完成数据操作,或者在发生错误 ...

  7. Spring Boot2 系列教程(十二)@ControllerAdvice 的三种使用场景

    严格来说,本文并不算是 Spring Boot 中的知识点,但是很多学过 SpringMVC 的小伙伴,对于 @ControllerAdvice 却并不熟悉,Spring Boot 和 SpringM ...

  8. Spring Boot2 系列教程(十四)CORS 解决跨域问题

    今天和小伙伴们来聊一聊通过CORS解决跨域问题. 同源策略 很多人对跨域有一种误解,以为这是前端的事,和后端没关系,其实不是这样的,说到跨域,就不得不说说浏览器的同源策略. 同源策略是由 Netsca ...

  9. Spring Boot2 系列教程(十五)定义系统启动任务的两种方式

    在 Servlet/Jsp 项目中,如果涉及到系统任务,例如在项目启动阶段要做一些数据初始化操作,这些操作有一个共同的特点,只在项目启动时进行,以后都不再执行,这里,容易想到web基础中的三大组件( ...

  10. Spring Boot2 系列教程(十六)定时任务的两种实现方式

    在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Qua ...

随机推荐

  1. UVa 1627 - Team them up!——[0-1背包]

    Your task is to divide a number of persons into two teams, in such a way, that: everyone belongs to ...

  2. linux Tasklets 机制

    tasklet 类似内核定时器在某些方面. 它们一直在中断时间运行, 它们一直运行在调度它 们的同一个 CPU 上, 并且它们接收一个 unsigned long 参数. 不象内核定时器, 但是, 你 ...

  3. linux 延后执行

    设备驱动常常需要延后一段时间执行一个特定片段的代码, 常常允许硬件完成某个任务. 在这一节我们涉及许多不同的技术来获得延后. 每种情况的环境决定了使用哪种技术最好; 我们全都仔细检查它们, 并且指出每 ...

  4. ios设备iframe无法滚动

    在使用IFRAME,你需要使用一个元素(如DIV)来包装他们 <div class="scroll-wrapper"> <iframe src="&qu ...

  5. 大数据vs计算机

    大数据有两个方向,一个是偏计算机的,另一个是偏经济的.你学过Java,所以你可以偏将计算机 基础1. 读书<Introduction to Data Mining>,这本书很浅显易懂,没有 ...

  6. Object 与 Function那神奇而混乱的搞基关系

    // Object 与 Function神奇而混乱的搞基关系... Object.__proto__ === Function.prototype; // true Object.__proto__ ...

  7. 从头学pytorch(三) 线性回归

    关于什么是线性回归,不多做介绍了.可以参考我以前的博客https://www.cnblogs.com/sdu20112013/p/10186516.html 实现线性回归 分为以下几个部分: 生成数据 ...

  8. 利用OGG进行数据库表的初始化

    OGG初始化 1.停止目标端re1进程 2.配置ei进程(若目标端有ei进程之前投递的文件则先清空) GGSCI (localhost) 1>add extract ei1, sourceist ...

  9. Oracle和可视化视图工具教程

    Oracle数据库安装教程 作者:黑小子-余 Qq:2931445528 微信:Y2931445528 可以找我,我有Oracle数据库安装包及工具   命令: Sqlplus /nolog Conn ...

  10. OPEN GL

    https://blog.csdn.net/cdut100/article/details/45753227 https://www.jianshu.com/p/d22cf555de47 https: ...