1、SpringBoot的配置文件
①、SpringBoot默认有两个全局的配置文件,配置文件名是固定的;
● application.properties
● application.yml
②、配置文件的作用:
因为SpringBoot在底层都给我们自动配置好了,所以使用配置文件可以修改SpringBoot自动配置的默认值;
③、YAML(YAML Ain't Markup Language):
YAML A Markup Language:是一个标记语言
YAML isn't Markup Language:不是一个标记语言;
YAML:以数据为中心,比json、xml等更适合做配置文件;
2、MYAL语法
①、YAML基本语法
– 使用缩进表示层级关系
– 建议使用空格。
– 缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
– 大小写敏感
k:(空格)v:表示一对键值对(空格必须有);
②、YAML 支持的三种数据结构
– 字面量:单个的、不可再分的值
– 对象:键值对的集合
– 数组:一组按次序排列的值
③、YAML三种数据结构常用写法
▲ 字面量:普通的值(数字,字符串,布尔、日期)
● k:(空格)v -> 字面量直接来写; 【字符串默认不用加上单引号或者双引号】
● 如果要加引号,单引号和双引号的区别:
△ "" :双引号,不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思
例如:name: "zhangsan \n lisi":输出;zhangsan 换行 lisi
△ '' :单引号,会转义特殊字符,特殊字符最终只是一个普通的字符串数据
例如:name: ‘zhangsan \n lisi’:输出;zhangsan \n lisi
▲ 对象、Map (属性和值) (键值对)
● k:(空格)v -> 对象名,在下一行来写对象的属性和值的关系,注意缩进 【对象还是k: v的方式】
例如:
friends:
lastName: zhangsan
age: 20
● 还有一种行内写法:
friends: {lastName: zhangsan,age: 18}
▲ 数组(List、Set)
● 用-(空格) 值表示数组中的一个元素
例如:
pets:
‐ cat
‐ dog
‐ pig
● 还有一种行内写法:
pets: [cat,dog,pig]
3、配置文件值注入到相应的JavaBean中
①、属性名匹配规则(Relaxed binding)
– person.firstName:张三
– person.first-name:张三
– person.first_name:张三
以上三种方式等价,作用是一样的
②、配置文件:
person:
username: hello
age: 18
boss: false
birth: 2017/12/12
maps: {k1: v1,k2: 12}
lists:
‐ lisi
‐ zhaoliu
dog:
name: 小狗
age: 12
★ 只需在对应的JavaBean上添加 @Component 注解 和 @ConfigurationProperties(prefix = "") 注解 即可完成配置文件值注入
例如:
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
*
* 1、@ConfigurationProperties : 告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
*
* 2、prefix = "person":配置文件中哪个下面的所有属性进行一一映射;
*
* 3、只有这个组件是容器中的组件,才能容器提供的 @ConfigurationProperties 功能,所以需要添加 @Component 注解;
*/
@Getter
@Setter
@ToString
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String username;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
}
★ 也可以使用Spring 底层的注解 @Value() 来获取配置文件中的值
③、@Value 获取值和 @ConfigurationProperties 获取值比较
@ConfigurationProperties @Value
功能 批量注入配置文件中的属性 一个个指定
松散绑定(松散语法) 支持 不支持
SpEL 不支持 支持
JSR303数据校验 支持 不支持
复杂类型封装 支持 不支持
▲ 无论配置文件是yml还是properties,@Value 和 @ConfigurationProperties都能获取到值;
▲ 如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
▲ 如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;
④、配置文件注入值数据校验
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
*
* 1、@ConfigurationProperties : 告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定;
*
* 2、prefix = "person":配置文件中哪个下面的所有属性进行一一映射;
*
* 3、只有这个组件是容器中的组件,才能容器提供的 @ConfigurationProperties 功能,所以需要添加 @Component 注解;
*
* 4、还可以使用Spring 底层的注解 @Value 来获取值
*
* 5、@ConfigurationProperties(prefix = "") 默认从全局配置文件中获取值;
*/
@Getter
@Setter
@ToString
@Component
@ConfigurationProperties(prefix = "person")
@Validated
public class Person {
/**
* <bean class="Person">
* <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"> </property>
* <bean/>
*/
//@Value("${person.last-name}")
private String lastName;
//@Value("#{10 * 2}")
private Integer age;
/**
* 1、@NotEmpty 是javax.validation.constraints下的
* 2、@Value() 不支持JSR303校验
*/
@NotEmpty
//@Value("true")
//@Value("")
private Boolean boss;
private Date birth;
/**
* 1、@Value("${person.maps}") : 会报错
*
* 2、@Value() 不支持复杂的类型封装
*/
private Map<String, Object> maps;
private List<Object> lists;
private Dog dog;
}
★ properties配置文件在idea中默认utf-8可能会乱码,因为IDEA使用的是utf-8编码,而properties使用的是ASCII

4、@PropertySource & @ImportResource & @Bean
①、 @PropertySource:加载指定的配置文件;
@Component
@ConfigurationProperties(prefix = "person")
@PropertySource(value = {"classpath:person.properties"})
public class Person {
【注意】:
1、使用 @PropertySource:加载指定的配置文件时,需要写 @ConfigurationProperties(prefix = "person") 注解,
并且使用prefix指定是配置文件中哪个下面的所有属性,否则获取不到属性值
2、如果指定的配置文件和本身自带的配置文件中都存在值,会优先使用本身自带的配置文件中的值,互补配置
②、@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效;
● Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别;
● 想让Spring的配置文件生效,加载进来,需要把 @ImportResource 注解标注在一个配置类【标注有@Configuration注解的类】上
例如 :
@ImportResource(locations = {"classpath:beans.xml"})
@Configuration
public class HelloService {
★ SpringBoot推荐给容器中添加组件的方式:推荐使用全注解的方式,而不是编写Spring的配置文件
● 配置类 @Configuration 相当于 Spring配置文件
● 使用 @Bean 给容器中添加组件
/**
* 1、@Configuration:指明当前类是一个配置类,就是来代替之前的Spring配置文件
*
* 2、在配置文件中用<bean><bean/>标签添加组件
*/
@Configuration
public class MyAppConfig {
//将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名
@Bean
public HelloService helloService() {
System.out.println("使用 @Bean 注解给springboot 容器添加组件了");
return new HelloService();
}
}
5、配置文件占位符
①、配置文件中可以使用随机数
${random.value}、${random.int}、${random.long}
${random.int(10)}、${random.int[1024,65536]}
②、占位符获取之前配置的值,如果没有可以是用:指定默认值
– 可以在配置文件中引用前面配置过的属性(优先级前面配置过的这里都能用)。
– ${app.name:默认值}来指定找不到属性时的默认值
例如:
person.last-name=里斯+${random.uuid}
person.age=${random.int}
person.dog.name=${person.last-name}_dog
person.dog.age=${person.myAge:12} //如果person中没有myAge属性时,就用默认值12
【注意】:
如果没有配置person.last-name属性和值,而这个属性又是类中有的属性,然后使用 person.dog.name=${person.last-name}_dog 或者
person.dog.name=${person.last-name:tom}_dog 都会报错
6、Profile
▲ Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活指定参数等方式快速切换环境
①、多profile文件形式
● 在主配置文件编写的时候,文件名可以是 application-{profile}.properties/yml
● 默认使用application.properties的配置;
②、yml支持多文档块方式
server:
port: 8081
spring:
profiles:
active: dev #指定激活哪个环境
---
server:
port: 8082
spring:
profiles: dev
---
server:
port: 8083
spring:
profiles: prod #指定属于哪个环境
③、激活指定profile的方式
● 1、在配置文件中指定 spring.profiles.active=dev
● 2、命令行:--spring.profiles.active=dev
java -jar spring-boot-02-config-0.0.1-SNAPSHOT.jar --spring.profiles.active=dev;
可以直接在测试的时候,配置传入命令行参数
● 3、虚拟机参数: -Dspring.profiles.active=dev

7、配置文件加载位置
①、spring boot 启动会扫描以下位置的application.properties或者application.yml文件作为Spring boot的默认配置文件
– file:./config/
– file:./
– classpath:/config/
– classpath:/
● 以上是按照优先级从高到低的顺序,所有位置的文件都会被加载【互补配置】,高优先级配置内容会覆盖低优先级配置内容
②、还可以通过spring.config.location来改变默认的配置文件位置
● 项目打包好以后,我们可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置;
指定配置文件和默认加载的这些配置文件共同起作用形成互补配置;
例如:
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --spring.config.location=G:/application.properties
【注意】:
spring.config.location=D:/BaiduNetdiskDownload/application.properties 写在配置文件中不起作用
8、外部配置加载顺序
①、SpringBoot也可以从以下位置加载配置; 优先级从高到低;高优先级的配置覆盖低优先级的配置,所有的配置会形成互补配置
● 1.命令行参数
所有的配置都可以在命令行上进行指定,多个配置用空格分开: --配置项=值
例如:
java -jar spring-boot-02-config-02-0.0.1-SNAPSHOT.jar --server.port=8087 --server.servlet.context-path=/abc
2.来自java:comp/env的JNDI属性
3.Java系统属性(System.getProperties())
4.操作系统环境变量
5.RandomValuePropertySource配置的random.*属性值
▲ 由jar包外向jar包内进行寻找;优先加载带profile
● 6.jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
● 7.jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
▲ 再来加载不带profile
● 8.jar包外部的application.properties或application.yml(不带spring.profile)配置文件
● 9.jar包内部的application.properties或application.yml(不带spring.profile)配置文件
10.@Configuration注解类上的@PropertySource
11.通过SpringApplication.setDefaultProperties指定的默认属性
②、所有支持的配置加载来源 --> 参考Springboot的官方文档第四部分Externalized Configuration
【链接】:https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#boot-features-external-config
9、自动配置原理
★ 配置文件到底能写什么?怎么写?
▲ 方式一:可以参考SpringBoot的官方文档
【链接】 https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#common-application-properties
▲ 方式二:熟悉SpringBoot的自动配置原理,
1)、SpringBoot启动的时候加载主配置类,开启了自动配置功能 @EnableAutoConfiguration
2)、@EnableAutoConfiguration 作用:利用AutoConfigurationImportSelector给容器中导入一些组件
● 可以查看selectImports()方法的内容;
List configurations = getCandidateConfigurations(annotationMetadata, attributes);获取候选的配置
● SpringFactoriesLoader.loadFactoryNames():
扫描所有jar包类路径下 META‐INF/spring.factories
把扫描到的这些文件的内容包装成properties对象
从properties中获取到EnableAutoConfiguration.class类(类名)对应的值,然后把他们添加在容器中
【总结】:
将类路径下 META-INF/spring.factories 里面配置的所有EnableAutoConfiguration的值加入到了容器中;
每一个 xxxAutoConfiguration 这样的类都是容器中的一个组件,都加入到容器中;用他们来做自动配置;
3)、每一个自动配置类进行自动配置功能;
4)、以HttpEncodingAutoConfiguration(Http编码自动配置)为例解释自动配置原理;
@Configuration //表示这是一个配置类,和以前编写的配置文件一样,可以给容器中添加组件
//启动指定类的ConfigurationProperties功能;将配置文件中对应的值和HttpEncodingProperties绑定起来;
// 并把HttpEncodingProperties加入到ioc容器中
@EnableConfigurationProperties(HttpEncodingProperties.class)
//Spring底层@Conditional注解,根据不同的条件,如果满足指定的条件,整个配置类里面的配置就会生效;
@ConditionalOnWebApplication // 判断当前应用是否是web应用,如果是,当前配置类生效
//判断当前项目有没有这个类CharacterEncodingFilter;SpringMVC中进行乱码解决的过滤器;
@ConditionalOnClass(CharacterEncodingFilter.class)
//判断配置文件中是否存在某个配置 spring.http.encoding.enabled;如果不存在,判断也是成立的
//matchIfMissing = true:即使我们配置文件中不配置pring.http.encoding.enabled=true,也是默认生效的;
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
//它已经和SpringBoot的配置文件映射了
private final HttpEncodingProperties properties;
//只有一个有参构造器的情况下,参数的值就会从容器中拿
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
@Bean //给容器中添加一个组件,这个组件的某些值需要从properties中获取
@ConditionalOnMissingBean(CharacterEncodingFilter.class) //判断容器中如果没有这个组件,则把这个组件添加到容器中
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name());
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
根据当前不同的条件判断,决定这个配置类是否生效?一但这个配置类生效;这个配置类就会给容器中添加各种组件;
这些组件的属性是从对应的properties类中获取的,这些类里面的每一个属性又是和配置文件绑定的;
5)、所有在配置文件中能配置的属性都是在xxxxProperties类中封装着;配置文件能配置什么就可以参照某个功能对应的这个属性类
@ConfigurationProperties(prefix = "spring.http.encoding") //从配置文件中获取指定的值和bean的属性进行绑定
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF‐8");
★ 精髓:
1)、SpringBoot启动会加载大量的自动配置类
2)、看我们需要的功能有没有SpringBoot默认写好的自动配置类;
3)、再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件有,我们就不需要再来配置了)
4)、给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们就可以在配置文件中指定这些属性的值;
★ 通用模式
– xxxAutoConfiguration:自动配置类
– xxxProperties:属性配置类
– yml/properties:文件中能配置的值就来源于[属性配置类]
10、查看详细的自动配置报告
在配置文件中配置: debug=true 默认是false , 可以在控制台打印自动配置报告,查看当前应用哪些自动配置起作用了,哪些没有起作用
11、@Conditional扩展
举例:
@ConditionalOnBean 如果容器中存在指定的Bean,则满足条件执行,否则不满足条件;
@ConditionalOnMissingBean 如果容器中不存在指定Bean,则满足条件执行,否则不满足条件;
网友评论