SpringBoot学习笔记-SpringBoot配置
Table of Contents
1 Spring Boot配置
1.1 配置文件
- SpringBoot使用一个全局的配置文件
application.properties
application.yml
: YAML(YAML Ain't Markup Language), 以数据为中心, 比json, xml更适合做配置文件.
server: port: 8081
- 配置文件的作用: 修改SpringBoot自动配置的默认值.
1.2 YAML语法
- 使用缩进表示层级关系.
- 缩进时不允许使用Tab键,只允许使用空格.
- 缩进空格数目不重要,只要相同层级的元素左侧对齐即可
- 大小写敏感
1.3 YAML的数据结构
- 对象: 键值对的集合.
- 数组: 一组按次序排列的值.
- 字面量: 单个的,不可再分的值.
1.3.1 字面量
- 字面量的字符串默认不用加上单引号或者双引号.
""
双引号, 不会转移字符串里面的特殊字符.- "zhangsan\nlisi" -> zhangsan换行lisi
''
单引号, 会转义特殊字符, 特殊字符最终只是一个普通的字符串数据.- "zhangsan\nlisi" -> zhangsan\nlisi
K: V: 字面量
1.3.2 对象
- 对象的语法是对象加属性的kv形式.
friends: lastName: zhangsan age: 20
- 行内写法
friends: {lastName: zhangsan, age: 18}
1.3.3 数组(List,Set)
- 用
-值
来表示数组的一个元素.
pets:
- cat
- dog
- pig
- 行内写法
pets: [cat,dog,pig]
1.4 获取yaml配置文件值注入
- yaml配置文件
person: lastName: zhangsan age: 18 boss: false birth: 2017/12/12 maps: {k1: v1, k2: 12} lists: - lisi - zhaoliu dog: name: 小狗 age: 2
- 组件bean
package com.devinkin.springboot.bean; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Date; import java.util.List; import java.util.Map; /** * 将配置文件中的每一个属性的值,映射到这个组件中 * @ConfigurationProperties 告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定 * prefix="person", 配置文件中哪个下面的所有属性进行一一映射 * * @Component 只有这个组件是容器中的组件,才能使用容器提供@ConfigurationProperties的功能. */ @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private Integer age; private Boolean boss; private Date birth; private Map<String, Object> maps; private List<Object> lists; public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Boolean getBoss() { return boss; } public void setBoss(Boolean boss) { this.boss = boss; } public Date getBirth() { return birth; } public void setBirth(Date birth) { this.birth = birth; } public Map<String, Object> getMaps() { return maps; } public void setMaps(Map<String, Object> maps) { this.maps = maps; } public List<Object> getLists() { return lists; } public void setLists(List<Object> lists) { this.lists = lists; } @Override public String toString() { return "Person{" + "lastName='" + lastName + '\'' + ", age=" + age + ", boss=" + boss + ", birth=" + birth + ", maps=" + maps + ", lists=" + lists + '}'; } }
- 导入配置文件处理器,以后编写配置就有提示了
<!-- 导入配置文件处理器, 配置文件进行绑定就会有提示 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
- 如果从properties配置文件中获取值注入,idea需要注意一下设置.
- 因为properties默认编码是ascii,而idea默认编码是utf-8
1.5 @Value获取值和@ConfigurationProperties获取值的比较
- 配置文件无论是yaml还是properties都能获取到值.
- 如果说我们只是在某个业务逻辑中需要获取一项配置文件的某项值,我们就使用
@Value
- 如果我们专门编写了一个javaBean来和配置文件进行校验,我们就直接使用
@ConfigurationProperties
@ConfigurationProperties | @Value | |
功能 | 批量注入配置文件的属性 | 一个个指定 |
松散绑定(松散语法) | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
1.6 配置文件注入值数据校验
- 使用
@Validated
注解.
@Component @ConfigurationProperties(prefix = "person") @Validated public class Person { /** * <bean class="Person"> * <property name="lastName" value="字面量"/${key}从环境变量,配置文件中获取值/#{SpEL}></property> * </bean> */ // @Value("${person.last-name}") // LastName必须是有效的格式 @Email private String lastName; }
1.7 @PropertySource和@ImportResource
@PropertySource
加载指定的配置文件- 例:
@PropertySource(value = {"classpath:person.properties"})
@ImportResource
导入Spring的配置文件, 让配置文件里面的内容生效.- SpringBoot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别.
- 想让Spring的配置文件加载进来, 把
@ImportResource
标注在主配置类上.
@ImportResource(locations = {"classpath:beans.xml"}) @SpringBootApplication public class SpringBoot02ConfigApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot02ConfigApplication.class, args); } }
- SpringBoot推荐给容器中添加组件的方式: 使用全注解的方式.
- 使用
@Bean
给容器中添加组件
- 使用
package com.devinkin.springboot.config; import com.devinkin.springboot.service.HelloService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @Configuration 它指明当前类是一个配置类,就是来替代之前的Spring配置文件 */ @Configuration public class MyAppConfig { /** * 将方法的返回值添加到容器中: 容器中这个组件默认的id就是方法名 * @return */ @Bean public HelloService helloService() { System.out.println("配置类@Bean给容器中添加组件了..."); return new HelloService(); } }
1.8 配置文件的占位符
- RandomValuePropertySource: 配置文件中可以使用随机数
${random.value}
${random.int}
${random.long}
${random.int(10)}
${random.int(1024,65536)}
- 属性配置占位符
- 可以在配置文件中引入前面配置过的属性(优先级前面配置过的这里都能用).
$app.name:默认值$
来指定找不到属性时的默认值.
# idea使用的是utf-8 # 配置person的值 person.last-name=张三${random.uuid} person.age=${random.int} person.birth=2019/02/01 person.boss=false person.maps.k1=v1 person.maps.k2=v2 person.lists=a,b,c person.dog.name=${person.last-name}_habi person.dog.age=15
1.9 Profile
- Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活,指定参数等方式快速切换环境.
- 多profile文件形式
- 格式:
application-{profile}.properties/yaml
- 格式:
- yaml多profile文档模式,
profiles
用于区分不同的文档.- 使用
---
分割多文档块.
- 使用
server: port: 8081 spring: profiles: active: dev --- server: port: 8082 spring: profiles: prod --- server: port: 8083 spring: profiles: dev ---
- 激活profile的方式
- 命令行:
--spring.profiles.active=dev
- 配置文件:
spring.profiles.active=dev
- jvm参数:
-Dspring.profiles.active=dev
- 命令行:
1.10 配置文件的加载位置
- SpringBoot启动会扫描一下位置下的
application.properties
或者application.yml
文件作为SpringBoot的默认配置文件.- 优先级从高到低的顺序,所有位置的文件都会被加载,高优先级配置内容会覆盖低优先级配置内容.
./config/
./
classpath:/config/
classpath:/
- SpringBoot会从这四个位置加载主配置文件: 互补配置.
- SpringBoot2.x弃用了
server.context-path
, 改用server.servlet.context-path
- SpringBoot2.x弃用了
- 可以配置
spring.config.location
来改变默认配置. 不过在项目调试的时候不会使用该配置.- 项目打包以后,我们可以使用命令行参数的形式,在项目启动的时候来指定配置文件的新位置.
- 指定的配置文件和默认加载的这些配置文件共同起作用, 互补配置.
1.11 外部配置加载顺序
- SpringBoot也可以从以下位置加载配置,优先级从高到低,高优先级的配置覆盖低优先级的配置,所有的配置会形成互补的配置.
- 命令行参数.
- 来自
java:comp/env
的JNDI
属性. - Java系统属性
System.getProperties()
- 操作系统环境变量.
- RandomValuePropertySource配置的
random.*
属性值. - jar包外部的
application-{profile}.properties
或application.yml
(带spring.profile) 配置文件 - jar包内部的
application-{profile}.properties
或application.yml
(带spring.profile) 配置文件 - jar包外部的
application-{profile}.properties
或application.yml
(不带spring.profile) 配置文件 - jar包内部的
application-{profile}.properties
或application.yml
(不带spring.profile) 配置文件 @Configuration
注解类上的@PropertySource
- 通过
SpringApplication.setDefaultProperties
指定的默认属性.
1.12 自动配置原理
- SpringBoot启动的时候加载主配置类,开启了自动配置功能
@EnableAutoConfiguration
@EnableAutoConfiguration
作用: 将类路径下的META-INF/spring.factories
里面配置的所有EnableAutoConfiguration
的值加到了容器中.- 利用
EnableAutoConfigurationImportSelector
给容器导入一些组件. - 查看
EnableAutoConfigurationImportSelector
其父类的selectImports
方法. List<String> configurations = getCandidateConfigurations(annotationMetadata,attributes);
获取候选的配置.SpringFactoriesLoader.loadFactoryNames()
扫描所有jar包类路径下的META-INF/spring.factories
- 把扫描到的这些文件的内容包装成
Properties
对象 - 从
Properties
中获取到EnableAutoConfiguration.class
类(类名)对应的值,然后把它们添加到容器中.
- 利用
- 每一个自动配置类进行自动配置功能.
- 以
HttpEncodingAutoConfiguration
为例解释自动配置原理.- 根据当前不同的条件判断,决定这个配置类是否生效.
@Configuration // 启动指定类的ConfigurationProperties功能 // 将配置文件中对应的值和HttpEncodingProperties绑定起来.并把 HttpEncodingProperties 加入到IOC容器中. @EnableConfigurationProperties(HttpEncodingProperties.class) // Spring底层@Conditional注解,根据不同得到条件,如果满足指定的条件,整个配置类里面的配置就会生效. // 判断当前应用是否为Web应用 @ConditionalOnWebApplication // 判断当前项目有没有CharacterFilter类(SpringMVC进行乱码解决的过滤器) @ConditionalOnClass(CharacterEncodingFilter.class) // 判断配置文件中是否存在某个配置 spring.http.encoding.enabled, 如果不存在, 判断也是成立的. // 即使配置文件中不配置 spring.http.encoding.enabled, 也是默认生效的. @ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) public class HttpEncodingAutoConfiguration {}
- 所有在配置文件中配置的属性都是在
xxxProperties
类中封装着, 配置文件能配置什么就可以参照某个功能对应的这个属性类.
// 从配置文件中获取指定的值和bean的属性进行绑定. @ConfigurationProperties(prefix = "spring.http.encoding") public class HttpEncodingProperties {}
- 给容器中添加一个组件, 这个组件的某些值需要从properties中获取.
@Bean @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; }
1.13 SpringBoot精髓
- SpringBoot启动会加载大量的自动配置类
- 看SpringBoot默认写好的自动配置类有没有我们需要的功能.
- 我们再来看自动配置类中到底配置了哪些组件.(只要我们使用的组件有,我们就不需要再来配置).
- 给容器中自动配置类添加组件的时候,会从
Properties
类中获取某些属性, 我们就可以在配置文件中指定这些属性的值.
1.14 @Condition派生注解
@Condition
作用: 指定的条件成立, 才给容器中添加组件, 配置类里面的所有内容才生效.- Condition注解的扩展
@Condition扩展注解 | 作用(判断是否满足当前指定条件) |
@ConditionOnJava | 系统的Java版本是否符合要求 |
@ConditionOnBean | 容器中存在指定Bean |
@ConditionOnMissingBean | 容器中不存在指定Bean |
@ConditionOnExpression | 满足SpEL表达式指定 |
@ConditionOnClass | 系统中有指定的类 |
@ConditionOnMissingClass | 系统中没有指定的类 |
@ConditionOnSingleCandidate | 容器中只有一个指定的Bean,或者这个Bean是首选Bean |
@ConditionOnProperty | 系统中指定的属性是否有指定的值 |
@ConditionOnResource | 类路径下是否存在指定资源文件 |
@ConditionOnWebApplication | 类路径下是否存在指定资源文件 |
- 在配置文件中添加如下配置
debug=true
启用debug模式, 可以查看加载了哪些自动配置类.