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
注解。
第二个办法,还有一种写的方式
第二个方式就是:
比如我们在配置类(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
就有俩个功能:
Car.java
下面的属性配置才能生效想要开启属性配置功能第一个你明显的标注@EnableConfigurationProperties()
开启谁的属性配置功能(这里只Car)。@Component
)中 , 它默认我们提供的这些功能他就能生效@Component
了。因为有些时候可能是这样子的:我们的这个Car有可能是引用的是第三方包里面的,第三方包里面的人家类里面有可能没标@Component,你是不是也不可能往人家写的类上标@Component
, 那咋办呢?我就可以用@EnableConfigurationProperties()
把人家的第三方包一整过来。@EnableConfigurationProperties
的俩个功能(1)开启了你的配置绑定(2)把你这个使用别人第三方包的组件自动注册到了容器中,我们还能测试生效@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
)失败,所以我们这一块报错了。
你要么就把它(@ConfigurationProperties
)加在容器(@Component
)中
要么就使用这种开启功能的方式(@EnableConfigurationProperties
)
这俩种都行,这是我们说的配置绑定,有了这个配置绑定那我们后来其实哪怕自定义的一些配置(比如 mycar.brand
和mycar.price
)你想绑给哪个JavaBean
就绑给哪个JavaBean
, 只是一个@ConfigurationProperties
注解的问题,我们不用再写以前一堆的代码,而且ConfigurationProperties
我们在未来SpringBoot
底层大家经常见到,你见到这个东西@ConfigurationProperties
就说明这个类(Car
)中的所有属性是跟SpringBoot
核心配置文件(application.properties
),你也不能随便写一个别的文件 它绑定不上,是跟我们application.properties
这个核心文件里面prefix = "mycar"
这个前缀下边的所有东西进行绑定的