时间:2023-02-27 10:34:36 | 栏目:JAVA代码 | 点击:次
SpringBoot底层的一个功能 : @ConfigurationProperties
来举一个场景例子 :
我们习惯于把经常变化的一个东西配到配置文件里面。比如把数据库的一些链接地址、账号、密码包括数据库连接池的大小等等这些属性配到properties配置文件里面,然后为了方便 , 因为我们未来可能要创建数据库连接池,我们会把这个配置文件里面的内容又一一解析到我们数据库连接池(比如javaBean我们这个对象里面),所以我们这个实现场景就是把properties里面的所有配置绑定JavaBean里面。那我们这个绑定过程如果用java原生代码来做还是挺麻烦的大概过程:
public class getProperties { public static void main(String[] args){ 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这个类我们加载来我们这个配置文件(pps.load(new FileInputStream("a.properties"));)然后遍历(while(enum1.hasMoreElements()))配置文件的每一个kv(key-value)值(String strKey = (String) enum1.nextElement(); String strValue = pps.getProperty(strKey););然后把kv值一一对应封装到JavaBean指定的属性里
其实这样还算简单的,复杂一点的就是:假设我给你个你的这个配置文件(application.properties)这个文件里面乱七八槽配置了100多行的配置,我让你在这100多行里面找数据与库有关的这四五行,那你可能会使用到正则表达式等等一大堆的东西你才能把它解析完成,但在SpringBoot里面,这个过程就会变得非常简单,我们把这个过程称为配置绑定;我们只需要一个注解@ConfigurationProperties
我在这举了个例子:
我在这写了一个Car.java的类
package com.chentianyu.boot.bean; 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 + "}"; } }
我们可以看做是JavaBean Car
Car有俩个属性:一个是brand(品牌),另一个是price(价格)
我现在想把跟Car有关的属性放到配置里面,我们就放springboot的application.properties这个配置文件里面。配置文件我随便写:比如我们直接写个mycar
application.properties
mycar.brand=BYD #我的汽车的这个品牌,比如BYD(比亚迪) mycar.price=100000 #我汽车的这个价格
现在我配了汽车的俩个信息;那如果是我们以前我们要读取这个配置文件我们要在Car.java里面封装很麻烦现在怎么做(一个注解,叫@ConfigurationProperties):
@ConfigurationProperties public class Car{...}
ConfigurationProperties.java
package org.springframework.boot.context.properties; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.springframework.core.annotation.AliasFor; import org.springframework.stereotype.Indexed; @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Documented @Indexed public @interface ConfigurationProperties { @AliasFor("prefix") String value() default ""; @AliasFor("value") String prefix() default ""; boolean ignoreInvalidFields() default false; boolean ignoreUnknownFields() default true; }
这个里面有我们要写的东西叫prefix(@AliasFor("prefix")),这个prefix跟这个value()其实都是互相都是别名(@AliasFor)
@ConfigurationProperties(prefix = "mycar") public class Car{...}
这个prefix指的是这个前缀,这个前缀的意思就是我们这个Car类里面的每一个属性跟配置文件哪个前缀下的属性一 一绑定。我们配置文件里面正好有mycar它的这个品牌名(brand)还有我们这个价格(price)跟我们JavaBean里面的品牌(brand)和价格(price)一模一样所以我就把mycar写上。
写上以后我们为了让它生效,我们把这个组件**加到容器(@Component)**中 , 因为我们容器中的组件才能拥有我们SpingBoot给它提供的强大功能(也就是容器提供的强大功能)
我们来测试一下:
我们Car组件(Car.java)它里的这些值是不是默认已经跟application.properties配置文件里面的mycar它下面的值一 一绑定上了?(写一个Controller进行测试)
HelloController.java
public Car car(){ return }
这个car从哪来? 因为我们用@Component放在容器中了,而且它这个容器中实例的每一个属性的值都跟配置文件中绑定的,所以我想要用的话,直接利用Spring的自动注入(@Autowired)把容器中的Car拿过来就行了
@Autowired Car car; @RequestMapping("/car")//处理一个请求 public Car car(){ return car;//我们返回这Car }
打开浏览器输入localhost:8080/car,得到的结果为:
{"brand":"BYD","price":100000}
包括我们配置文件改了:
mycar.brand=YD #我的汽车的这个品牌,比如BYD(比亚迪) mycar.price=100000 #我汽车的这个价格
注意:配置文件改了我们程序一定要重新启动
然后重新测试:
{"brand":"YD","price":100000}
所以现在想要让一个JavaBean与配置文件里面的东西一 一绑定,我们第一种办法就是@ConfigurationProperties注解 , 我们容器中的组件,标注@ConfigurationProperties注解。
这个方式叫@Component + @ConfigurationProperties
第二个办法,还有一种写的方式
第二个方式就是:
@EnableConfigurationProperties + @ConfigurationProperties
比如我们在配置类(MyConfig)里面(第二种方式一定要在配置类里面写,因为配置类首先是容器中的组件(@Configuration))然后我们在配置类上写什么才能生效?写一个@EnableConfigurationProperties意思就是开启我们这个属性配置功能,开启谁的属性配置功能?我们这个Car想要跟人绑定所以我们把Car
传进@EnableConfigurationProperties()里面来:
@Configuration(proxyBeanMethods = false)//告诉SpringBoot这是一个配置类(把这个类说明@Configuration类似于告诉spring这个文件是配置文件)
@ConditionalOnMissingBean(name = "tom") @ImportResource("classpath:beans.xml") @EnableConfigurationProperties(Car.class) public class MyConfig {...}
那我们这个@EnableConfigurationProperties就有俩个功能:
1、开启Car的配置绑定(属性配置)功能
2、把这个组件自动注册到容器中(这里指Car这个组件)
我们不用@EnableConfigurationProperties我们只说Car是属性绑定(@ConfigurationProperties)而且没把它加在容器(@Component)中。
***************************
APPLICATION FAILED TO START
***************************Description:
Field car in com.chentianyu.boot.controller.HelloController required a bean of type 'com.chentianyu.boot.bean.Car' that could not be found.
The injection point has the following annotations:
- @org.springframework.beans.factory.annotation.Autowired(required=true)Action:
Consider defining a bean of type 'com.chentianyu.boot.bean.Car' in your configuration.
Process finished with exit code 1
我们启动都报错了,报错的原因就是HelloController.java里面有用Car这个Car在容器中没有,所以拿不到,自动装配(@Autowired)失败,所以我们这一块报错了。
这俩种都行,这是我们说的配置绑定,有了这个配置绑定那我们后来其实哪怕自定义的一些配置(比如 mycar.brand和mycar.price)你想绑给哪个JavaBean就绑给哪个JavaBean , 只是一个@ConfigurationProperties注解的问题,我们不用再写以前一堆的代码,而且ConfigurationProperties我们在未来SpringBoot底层大家经常见到,你见到这个东西@ConfigurationProperties就说明这个类(Car)中的所有属性是跟SpringBoot核心配置文件(application.properties),你也不能随便写一个别的文件 它绑定不上,是跟我们application.properties这个核心文件里面prefix = "mycar"这个前缀下边的所有东西进行绑定的