- 1. @ConfigurationProperties
- —————————————————————普通属性测试
- —————————————————————简单集合与数组测试
- 等价于
- myListOrArray: [d,e,f] myListOrArray: d,e,f
- 二维数组
- myListOrArray: [[d],[e],[f]]
- myListOrArray:
- -
- - d
- - e
- - f
- -
- - c
- —————————————————————简单Map测试
- 等价于
- myMap: {k4: v4,k5: v5,k6: v6}
- 等价于
- myMap[k1]: v1
- myMap[k2]: v2
- myMap[k3]: v3
- —————————————————————对象测试
- 等价于
- myUser: {name: 王五,age: 50,gender: 男,motto: 好好1}
- —————————————————————复杂集合与数组测试
- 等价于
- myListOrArrayPlus:
- - {name: 王五,age: 50,gender: 男,motto: 好好2}
- - {name: 王五1,age: 50,gender: 男,motto: 好好2}
- 等价于
- myListOrArrayPlus:
- -
- name: 王五2
- —————————————————————复杂Map测试
- myMapPlus: {k1: {name: 王五,age: 50,gender: 男,motto: 好好1},k2: {name: 王五1,age: 50,gender: 男,motto: 好好1}}
1. @ConfigurationProperties
@ConfigurationProperties是springboot提供读取配置文件的一个注解。其对应的bean的后置处理器为ConfigurationPropertiesBindingPostProcessor
public class ConfigurationPropertiesBindingPostProcessorimplements BeanPostProcessor, PriorityOrdered, ApplicationContextAware, InitializingBean {
它是实现了BeanPostProcessor接口,在bean被实例化后,会调用后置处理,递归的查找属性,通过反射注入值,对大多数属性而言强制需提供其setter和getter方法。
但是属性名称不要求一定相同,只需保证配置文件的属性和setter方法名相同即可。
不过@ConfigurationProperties注解,只可以把应用主配置文件的内容读取进来,要想给Bean赋值,只能读取主配置文件,就是application.properties或者application.yml文件,若我们想自己写一个配置文件来给bean赋值,我们就可以使用该注解@PropertyResource
我们在resource里边新建一个student.properties文件,并把之前主配置文件里的内容剪贴进来,并在bean上边加上注解
@Component@ConfigurationProperties(prefix = "student")@PropertyResource(value = {"classpath:student.properties"})// value可以添加多个配置文件,classpath指的是类路径,表示类路径下的student.properties文件public class Student {......}
1.@ConfigurationProperties读取配置文件,注入bean的三种方式
1. 配合@Component注解直接进行注入(主要)
@Component@ConfigurationProperties(prefix = "student")public class Student {......}
2. 使用@EnableConfigurationProperties,通常配置在标有@Configuration的类上,当然其他@Component注解的派生类也可以,不过不推荐.(摘取)(springboot源码大量使用,例如DataSourceAutoConfiguration,FreeMarkerAutoConfiguration)
@ConfigurationProperties(prefix = "doc")public class DocumentServerProperties {//代码...}//@EnableConfigurationProperties的作用:使@ConfigurationProperties注解的类生效,并将标注@ConfigurationProperties注解的类注册到spring容器中//@EnableConfigurationProperties({DocumentServerProperties.class}) 只是让DocumentServerProperties这个类生效,并将其注册到spring容器中@EnableConfigurationProperties@Configurationpublic class SomeConfiguration {}
3. 使用@Bean方式在标有@Configuration的类进行注入,这种方式通常可以用在对第三方类进行配置属性注册(摘取)
public class ThirdComponent {...}@Configurationpublic class SomeConfiguration {@ConfigurationProperties("demo")@Beanpublic ThirdComponent thirdComponent(){return new ThirdComponent();}}
2. @ConfigurationProperties(yml/properties) 和 @Value(“xx”) 区别
3. @ConfigurationProperties绑定配置信息至Array、List、Map、Bean的实现
如果application.properties与自定义的 properties有重复的属性,取application.properties配置的属性值
@Datapublic class User {private String name;private Integer age;private String gender;private String motto;}
@Component@ConfigurationProperties(prefix = "prop")@Datapublic class DemoConfig {private String normalString;private Integer normalNumber;private Boolean normalBoolean;/*** 类型为数组或者集合都可以*/private String[] myListOrArray;private Map<String, Object> myMap;private User myUser;/*** 类型为数组或者集合都可以*/private List<User> myListOrArrayPlus;private Map<String, User> myMapPlus;}
1. application.properties
#------------------------------------------普通属性测试prop.normalString = value1prop.normalNumber = 123prop.normalBoolean = false#------------------------------------------简单集合与数组测试prop.myListOrArray[0] = aprop.myListOrArray[1] = bprop.myListOrArray[2] = c# 等价于# prop.myListOrArray = a,b,c#------------------------------------------简单Map测试prop.myMap[k1] = v1prop.myMap[k2] = v2prop.myMap[k3] = v3# 等价于# prop.myMap.k1 = v1# prop.myMap.k1 = v1# prop.myMap.k1 = v1#------------------------------------------对象测试prop.myUser.name = 张三prop.myUser.[age] = 28prop.myUser.gender = 男prop.myUser.motto = 岁月# 等价于# prop.myUser[name] = 张三# prop.myUser[age] = 28# prop.myUser[gender] = 男# prop.myUser[motto] = 岁月静好#------------------------------------------复杂集合与数组测试prop.myListOrArrayPlus[0].name = 张三prop.myListOrArrayPlus[0].age = 28prop.myListOrArrayPlus[0].gender = 男prop.myListOrArrayPlus[0].motto = 岁月prop.myListOrArrayPlus[1].name = 李四prop.myListOrArrayPlus[1].age = 28prop.myListOrArrayPlus[1].gender = 女prop.myListOrArrayPlus[1].motto = 年华# 等价于# prop.myListOrArrayPlus[0][name] = 张三# prop.myListOrArrayPlus[0][age] = 28# prop.myListOrArrayPlus[0][gender] = 男# prop.myListOrArrayPlus[0][motto] = 岁月# prop.myListOrArrayPlus[1][name] = 李四# prop.myListOrArrayPlus[1][age] = 28# prop.myListOrArrayPlus[1][gender] = 女# prop.myListOrArrayPlus[1][motto] = 年华#------------------------------------------复杂Map测试prop.myMapPlus[k1].name = 张三prop.myMapPlus[k1].age = 28prop.myMapPlus[k1].gender = 男prop.myMapPlus[k1].motto = 岁月prop.myMapPlus[k2].name = 李四prop.myMapPlus[k2].age = 28prop.myMapPlus[k2].gender = 女prop.myMapPlus[k2].motto = 年华# 等价于# prop.myMapPlus.k1.name = 张三# 等价于# prop.myMapPlus[k1][name] = 张三# 等价于# prop.myMapPlus.k1[name] = 张三
中文属性值乱码问题:
Spring Boot注解读取application.properties或者application-{profile}.properties文件时默认的是ISO-8859-1编码。
如果使用@PropertySource,可以设置encoding属性值为UTF-8,properties文件编码也设置为UTF-8
@Component@ConfigurationProperties(prefix = "prop")@PropertySource(value={"classpath:demo.properties"},encoding = "UTF-8")@Datapublic class DemoConfig {
-
2. application.yml
```java
—————————————————————普通属性测试
prop: normalString : normalString normalNumber : 456 normalBoolean : true
—————————————————————简单集合与数组测试
myListOrArray:
- d- e- f
等价于
myListOrArray: [d,e,f] myListOrArray: d,e,f
二维数组
myListOrArray: [[d],[e],[f]]
myListOrArray:
-
- d
- e
- f
-
- c
—————————————————————简单Map测试
myMap: k4: v4 k5: v5 k6: v6
等价于
myMap: {k4: v4,k5: v5,k6: v6}
等价于
myMap[k1]: v1
myMap[k2]: v2
myMap[k3]: v3
—————————————————————对象测试
myUser: name: 王五 age: 50 gender: 男 motto: 好好
等价于
myUser: {name: 王五,age: 50,gender: 男,motto: 好好1}
—————————————————————复杂集合与数组测试
myListOrArrayPlus: [{name: 王五,age: 50,gender: 男,motto: 好好1},{name: 王五1,age: 50,gender: 男,motto: 好好1}]
等价于
myListOrArrayPlus:
- {name: 王五,age: 50,gender: 男,motto: 好好2}
- {name: 王五1,age: 50,gender: 男,motto: 好好2}
等价于
myListOrArrayPlus:
-
name: 王五2
—————————————————————复杂Map测试
myMapPlus: k1: {name: 王五,age: 50,gender: 男,motto: 好好1} k2: {name: 王五1,age: 50,gender: 男,motto: 好好1}
myMapPlus: {k1: {name: 王五,age: 50,gender: 男,motto: 好好1},k2: {name: 王五1,age: 50,gender: 男,motto: 好好1}}
<a name="dZQ9P"></a>#### 3. 测试```java@SpringBootTestclass Demo2021ApplicationTests {@AutowiredDemoConfig demoConfig;@Testvoid contextLoads() {System.out.println(demoConfig);}}
2. @ImportResource
导入Spring的配置文件,让配置文件里边的内容生效.我们在使用spring的时候,通常会用xml去配置bean然后注入数据.
这对 Spring Boot 兼容老项目非常有用,因为有些配置无法通过 Java Config 的形式来配置就只能用这个注解来导入。
3. @Configuration和@Bean
Spring新的配置体系中最为重要的构件是:@Configuration标注的类,@Bean标注的方法。
简单粗暴理解:@Configuration标注的类等同于一个xml文件,@Bean标注的方法等同于xml文件里的一个
// @since 3.0@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic @interface Configuration {@AliasFor(annotation = Component.class)String value() default "";/*** @since 5.2*/boolean proxyBeanMethods() default true;}
Full模式和Lite模式
Full模式和Lite模式均是针对于Spring配置类而言的,和xml配置文件无关。值得注意的是:判断是Full模式 or Lite模式的前提是,首先你得是个容器组件。
Lite模式
当@Bean方法在没有使用@Configuration注释的类中声明时,它们被称为在Lite模式下处理。它包括:在@Component中声明的@Bean方法,甚至只是在一个非常普通的类中声明的Bean方法,都被认为是Lite版的配置类。@Bean方法是一种通用的工厂方法(factory-method)机制。
何时为Lite模式
官方定义为:在没有标注@Configuration的类里面有@Bean方法就称为Lite模式的配置。透过源码再看这个定义是不完全正确的,而应该是有如下case均认为是Lite模式的配置类:类上标注有@Component注解类上标注有@ComponentScan注解类上标注有@Import注解类上标注有@ImportResource注解若类上没有任何注解,但类内存在@Bean方法以上case的前提均是类上没有被标注@Configuration,在Spring 5.2之后新增了一种case也算作Lite模式:标注有@Configuration(proxyBeanMethods = false),注意:此值默认是true哦,需要显示改为false才算是Lite模式细心的你会发现,自Spring5.2(对应Spring Boot 2.2.0)开始,内置的几乎所有的@Configuration配置类都被修改为了@Configuration(proxyBeanMethods = false),目的何为?答:以此来降低启动时间,为Cloud Native继续做准备。
Lite模式优缺点
优点:运行时不再需要给对应类生成CGLIB子类,提高了运行性能,降低了启动时间可以该配置类当作一个普通类使用喽:也就是说@Bean方法 可以是private、可以是final缺点:不能声明@Bean之间的依赖,也就是说不能通过方法调用来依赖其它Bean(其实这个缺点还好,很容易用其它方式“弥补”,比如:把依赖Bean放进方法入参里即可)
总结
该模式下,配置类本身不会被CGLIB增强,放进IoC容器内的就是本尊该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式该模式下,配置类内部不能通过方法调用来处理依赖,否则每次生成的都是一个新实例而并非IoC容器内的单例该模式下,配置类就是一普通类嘛,所以@Bean方法可以使用private/final等进行修饰(static自然也是阔仪的)
Full模式
在常见的场景中,@Bean方法都会在标注有@Configuration的类中声明,以确保总是使用“Full模式”,这么一来,交叉方法引用会被重定向到容器的生命周期管理,所以就可以更方便的管理Bean依赖。
何时为Full模式
标注有@Configuration注解的类被称为full模式的配置类。自Spring5.2后这句话改为下面这样我觉得更为精确些:标注有@Configuration或者@Configuration(proxyBeanMethods = true)的类被称为Full模式的配置类(当然喽,proxyBeanMethods属性的默认值是true,所以一般需要Full模式我们只需要标个注解即可)
Full模式优缺点
优点:可以支持通过常规Java调用相同类的@Bean方法而保证是容器内的Bean,这有效规避了在“Lite模式”下操作时难以跟踪的细微错误。特别对于萌新程序员,这个特点很有意义缺点:运行时会给该类生成一个CGLIB子类放进容器,有一定的性能、时间开销(这个开销在Spring Boot这种拥有大量配置类的情况下是不容忽视的,这也是为何Spring 5.2新增了proxyBeanMethods属性的最直接原因)正因为被代理了,所以@Bean方法 不可以是private、不可以是final
总结
该模式下,配置类会被CGLIB增强(生成代理对象),放进IoC容器内的是代理该模式下,对于内部类是没有限制的:可以是Full模式或者Lite模式该模式下,配置类内部可以通过方法调用来处理依赖,并且能够保证是同一个实例,都指向IoC内的那个单例该模式下,@Bean方法不能被private/final等进行修饰(很简单,因为方法需要被复写嘛,所以不能私有和final。defualt/protected/public都可以哦),否则启动报错(其实IDEA编译器在编译器就提示可以提示你了)
使用建议
- 如果是在公司的业务功能/服务上做开发,使用Full模式
- 如果你是个容器开发者,或者你在开发中间件、通用组件等,那么使用Lite模式是一种更被推荐的方式,它对Cloud Native更为友好
