Spring Boot 2从入门到入坟 | 底层注解篇:@ConfigurationProperties配置绑定
发布日期:2021-06-30 17:57:22 浏览次数:3 分类:技术文章

本文共 9017 字,大约阅读时间需要 30 分钟。

在这篇文章中,我们再来说一个Spring Boot的底层注解,即@ConfigurationProperties。

@ConfigurationProperties注解出现的背景

我们还是举一个例子来说明吧!我们总是习惯于把经常爱变化的一些东西配到配置文件里面,比如我们小时候在学Java的时候,尤其是在数据库开发的时候,是不是经常要把数据库的连接信息,诸如数据库的url连接地址、账号、密码以及数据库连接池的大小等等,配到properties配置文件中啊!然后,未来等到我们需要创建数据库连接池时,再将properties配置文件里面的内容一一解析出来,接着就能创建数据库连接池了,其实呢,数据库连接池就是一个JavaBean,所以,总的来说,这个案例场景就是要把properties配置文件里面的所有配置绑定到JavaBean里面。

那么如何来实现这个绑定过程呢?如果我们还是使用Java原生代码来做,那么这还是挺麻烦的,大概代码就像是下面这样。

public class getProperties {
public static void main(String[] args) throws FileNotFoundException, IOException {
Properties pps = new Properties(); pps.load(new FileInputStream("a.properties")); Enumeration enum1 = pps.propertyNames(); // 得到配置文件的名字 while(enum1.hasMoreElements()) {
String strKey = (String) enum1.nextElement(); String strValue = pps.getProperty(strKey); System.out.println(strKey + "=" + strValue); // 封装到JavaBean... } }}

我们是使用Properties这个类来加载我们的配置文件的。然后,再来遍历配置文件里面的每一对key-value值,最后,再把这对对key-value值一一对应封装到JavaBean指定的属性里面。你是不是感觉写Java原生代码也能接受啊?小了,你格局小了!那是你没碰到复杂情况,如果要是别人给你的配置文件,里面乱七八糟,配置了100多行的东东,假设我要你在这100多行的配置里面找到跟数据库连接信息有关的配置,也就那么4、5行,那么这时你该怎么办?是不是有可能需要用到正则表达式等等一大堆的东西,你才可能解析完成啊!

但是,在Spring Boot里面,这个过程就会变得非常简单了,而且我们还会把这个过程称为配置绑定哟。这样,@ConfigurationProperties注解就应运而生了!

读取配置文件里面配置的值,并将其封装到JavaBean相应的属性中

@Component + @ConfigurationProperties

这儿,不妨我们来使用一下@ConfigurationProperties注解吧!我是以一个案例来说明的哟!首先,新建一个类,例如Car.java,如下所示。

package com.meimeixia.boot.bean;/** * @author liayun * @create 2021-04-24 0:43 * 汽车 */public class Car {
private String brand; // 品牌 private Integer price; // 价格 public String getBrand() {
return brand; } public void setBrand(String brand) {
this.brand = brand; } public Integer getPrice() {
return price; } public void setPrice(Integer price) {
this.price = price; } @Override public String toString() {
return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; }}

现在我们想把跟汽车有关的东西都放到配置文件里面,例如application.properties,在该properties配置文件中,你想怎么写都行,比如就写成下面这样也行。

mycar.brand=BYDmycar.price=100000

OK,现在我们是配了汽车的两个信息,如果是以前我们要读取这个配置文件,并且还要将读取出来的配置信息封装到Car对象里面,势必是非常麻烦的,既然麻烦,那么又该怎么办呢?很简单,现在只须使用一个@ConfigurationProperties注解即可,该注解翻译过来就是配置属性的意思,我们不妨点进它里面去看一看它的源码,如下图所示。

在这里插入图片描述

可以看到它里面有一个prefix属性,而且很奇怪的一点是该属性上还标注了一个@AliasFor("value")注解,好像是在说prefix的别名也是value,不仅如此,它里面value属性上同样也标注了一个@AliasFor("prefix")注解,我想prefix和value这俩属性应该都是互为彼此的,你就是我,我就是你,也即互为别名。

于是,我们不妨就在Car类上标注上@ConfigurationProperties(prefix = "mycar")这样一个注解,其中prefix属性是来指定前缀的,前缀的意思就是说,我们的这个Car类里面的每一个属性跟配置文件哪个前缀下的所有属性一一绑定。而咱们在配置文件里面写的前缀正好是mycar,在其下面还有一个brand(汽车的品牌)和一个price(汽车的价格)这俩玩意,它俩跟我们JavaBean里面(即Car类)的两个属性一模一样,所以像下面这样写是没有问题的。

在这里插入图片描述

但是,你发现没有该注解下面居然有红色波浪线,这就表示这样写不对呗,原因何在呢?这是因为在类上标注了该注解之后,为了让其生效,我们还得将该类型的组件添加到容器中,因为只有容器中的组件才能拥有Spring Boot提供的强大功能,也就是容器提供的强大功能,比如配置绑定,大家一定要记住这点哟!

于是,我们还得在Car类上标注一个@Component注解,如下所示。

package com.meimeixia.boot.bean;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;/** * @author liayun * @create 2021-04-24 0:43 * 汽车 *//** * 只有在容器中的组件,才会拥有Spring Boot提供的强大功能 */@Component@ConfigurationProperties(prefix = "mycar")public class Car {
private String brand; // 品牌 private Integer price; // 价格 public String getBrand() {
return brand; } public void setBrand(String brand) {
this.brand = brand; } public Integer getPrice() {
return price; } public void setPrice(Integer price) {
this.price = price; } @Override public String toString() {
return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; }}

现在,以上Car类型的组件里面的每一个属性默认已经跟配置文件里面前缀mycar下面的所有属性一一绑定上了。为了证明这一点,我们可以在HelloController里面编写如下一个car方法来进行测试。

package com.meimeixia.boot.controller;import com.meimeixia.boot.bean.Car;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.RestController;/** * @author liayun * @create 2021-04-19 4:24 */@RestControllerpublic class HelloController {
@Autowired Car car; // car实例里面每一个属性的值都是跟配置文件进行绑定的 @RequestMapping("/car") public Car car() {
return car; } @RequestMapping("/hello") public String handle01(@RequestParam("name") String name) {
return "Hello, Spring Boot 2!" + "你好:" + name; }}

好,现在来启动咱们的Spring Boot应用,启动成功之后,我们通过浏览器访问car请求,看能不能得到配置文件里面配置的东东。

在这里插入图片描述

发现配置文件里面配置的BYD100000这俩值都能被封装到Car对象相应的属性中,显然我们成功验证了这一点。

如果我们修改了配置文件,例如修改成了下面这个样子,那么还能读取到配置文件里面配置的值,并将其封装到Car对象相应的属性中吗?

mycar.brand=YDmycar.price=100000

想都不用想,一定能够的。你要是不信,不妨自己来亲手测试一下。注意,配置文件修改了之后,咱们的Spring Boot应用一定要重新启动哟😘

在这里插入图片描述

可以看到,以上结论是没有任何问题的。

现在,大家看到没有,要想让一个JavaBean里面的属性跟配置文件里面的东东一一绑定,那是不是可太简单了啊!

以上我们只是讲解了其中的一种方式,即给容器中的组件标注@ConfigurationProperties注解,也就是联合使用@Component和@ConfigurationProperties这俩注解。除此之外,还有一种方式,还算是简单吧!即联合使用@EnableConfigurationProperties和@ConfigurationProperties这俩注解,下面我就来为大家详细讲解下这种方式。

@EnableConfigurationProperties + @ConfigurationProperties

大家可能会有这样一个疑问,@EnableConfigurationProperties注解到底应该写在哪儿呢?大家可一定要注意了,该注解一定要写在配置类里面,因为配置类本身就是容器中的一个组件。

package com.meimeixia.boot.config;import ch.qos.logback.core.db.DBHelper;import com.meimeixia.boot.bean.Car;import com.meimeixia.boot.bean.Pet;import com.meimeixia.boot.bean.User;import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.context.annotation.Import;import org.springframework.context.annotation.ImportResource;/** * @author liayun * @create 2021-04-23 19:42 * */@Import({
User.class, DBHelper.class}) // 这时,就会给容器中自动创建出这两个类型的组件了@Configuration(proxyBeanMethods = true) // 告诉Spring Boot这是一个配置类 == 配置文件//@ConditionalOnBean(name = "tom")@ConditionalOnMissingBean(name = "tom")@ImportResource("classpath:beans.xml")@EnableConfigurationProperties(Car.class)// 1. 开启Car配置绑定功能// 2. 把Car这个组件自动注册到容器中public class MyConfig {
@Bean // @Bean注解是给容器中添加组件的。添加什么组件呢?以方法名作为组件的id,返回类型就是组件类型,返回的值就是组件在容器中的实例 public User user01() {
User zhangsan = new User("zhangsan", 18); // User类型的组件依赖了Pet类型的组件 zhangsan.setPet(tomcatPet()); return zhangsan; }// @Bean("tom") @Bean("tom666") public Pet tomcatPet() {
return new Pet("tomcat"); }}

可以看到,我们在配置类上写了@EnableConfigurationProperties(Car.class)这样一个注解,意思就是开启Car类型组件的配置绑定功能,因为是Car类型组件想要跟人家进行绑定的,所以我们得把Car.class传进来。你只有开启了Car类型组件的配置绑定功能,接下来的像@ConfigurationProperties(prefix = "mycar")这样的注解才能生效,也就是才能读取配置文件里面配置的值,并将其封装到JavaBean相应的属性中。不知道我这样理解是不是对的,如有错,请及时反馈给我!

想要开启配置绑定功能,你明显的使用@EnableConfigurationProperties注解开启谁的配置绑定功能就行。

其实,@EnableConfigurationProperties(Car.class)注解除了具备以上功能之外,还有一个功能,那就是将你指定类型的组件自动注册到容器中。也就是说,只要用了@EnableConfigurationProperties这么一个注解之后,那我们就不必再写@Component注解了。

package com.meimeixia.boot.bean;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.stereotype.Component;/** * @author liayun * @create 2021-04-24 0:43 * 汽车 *//** * 只有在容器中的组件,才会拥有Spring Boot提供的强大功能 *///@Component@ConfigurationProperties(prefix = "mycar")public class Car {
private String brand; // 品牌 private Integer price; // 价格 public String getBrand() {
return brand; } public void setBrand(String brand) {
this.brand = brand; } public Integer getPrice() {
return price; } public void setPrice(Integer price) {
this.price = price; } @Override public String toString() {
return "Car{" + "brand='" + brand + '\'' + ", price=" + price + '}'; }}

因为有些时候可能是这样子的,我们使用的组件极有可能是引用的第三方包里面的,在人家第三方包里面,万一人家类里面没有标注@Component注解,难道你还硬要给人家类头上标啊?这不是头铁吗?那这时咋办呢?使用@EnableConfigurationProperties注解不就完了吗?它就有两个功能,而且我上面也说过了,这里再讲一遍。

  1. 开启(指定类型组件的)配置绑定功能
  2. 将指定类型的组件自动注册到容器中

此时,我们不妨再次重新启动Spring Boot应用,再来访问一下car请求,发现访问结果如下。

在这里插入图片描述

可以看到,测试是没有任何问题的。而且,咱们容器中还有一个Car类型的组件,如下图所示。

在这里插入图片描述

如果我们现在没有在配置类上标注@EnableConfigurationProperties(Car.class)这么一个注解,也就是还没有将Car类型的组件自动注册到容器中,那么你觉得会发生什么现象呢?此时,你会发现Car类上标注的@ConfigurationProperties(prefix = "mycar")注解下面有红色波浪线,如下图所示。

在这里插入图片描述

这说明代码编译都通不过,那接下去还干个鸟事啊!而且,除了这个错误之外,HelloController里面自动注入的Car实例也被画了一个红色波浪线,如下图所示。

在这里插入图片描述

这是因为Car类型的实例在容器中压根就不存在,又何来的自动注入呢?你说是不是啊!所以,你要么是将Car类型的组件添加在容器中(即标注@Component注解),要么是开启其配置绑定功能(即标注@EnableConfigurationProperties注解),这两种方式你任选其一都行。

以上就是我们说的配置绑定。有了配置绑定,我们以后在配置文件里面自定义一些配置时,比如我们自定义配了一些与汽车的相关东东,想将这些配置的东东绑定给哪个JavaBean就绑定给哪个JavaBean,这也就是一个注解的事,我们再也不用像以前一样写那么一大堆的代码了。另外,像@ConfigurationProperties(prefix = "mycar")这样的注解,我们未来在Spring Boot底层会经常见到,见到它之后,你就能明白被该注解标注的类里面的所有属性是跟Spring Boot核心配置文件(即application.properties)里面前缀(例如mycar)下面的所有东西进行一一绑定的。注意,你不能乱七八糟写一个其他的文件,这肯定是绑定不上的。

转载地址:https://liayun.blog.csdn.net/article/details/116310499 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Spring Boot 2从入门到入坟 | 自动配置篇:源码分析之自动包规则原理
下一篇:Spring Boot 2从入门到入坟 | 底层注解篇:使用@ImportResource注解导入Spring配置文件

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月28日 13时56分51秒