进阶
# 原理初探:自动配置
# pom.xml
spring-boot-depencties
的依赖都在pom.xml的父工程中- 我们在引入一些springboot依赖的时候不需要引入版本就是因为在父工程中的依赖都配置好了版本
所以我们通过查看源码可以得出:
pom.xml
的父工程的父工程管理着所有的依赖和版本,所以我们在设置启动器的时候才不用规定版本
# 启动器
那么说到了启动器,启动器又是什么呢?
启动器说白了就是Spring Boot的启动场景
在上面的这张图中,我们可以看到,pom.xml
的依赖中其实就是一个又一个的启动器
其中spring-boot-starter
是总启动器,也就是说只有靠它才能启动spring boot项目
下面还有启动器,图中只标注除了test启动器
我们的web环境其实也是依赖于一个启动器,就是spring-boot-stater-web
,有了这个启动器,它会帮我们自动导入web环境所有依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
有了这些启动器,启动场景就会启动,而启动器其实都是依赖于刚才说的pom.xml
的所有依赖
启动器几乎包含了我们能想象到的所有的场景,所以我们要什么环境直接加上一个启动器就好了
启动器的所有依赖自然在官网上有:所有的依赖版本
所有的启动器:
# 主程序
主程序看上去很简单,只有一个注解和启动方法
# 注解
通过查看源码,我们可以得出一个流程图
最后得到的文件:
那么Spring Boot在启动的时候,从类路径下:META-INF/spring.factories
获取指定的值
将这些自动配置的类导入容器,自动配置就会生效并且帮我进行自动配置
以前我们需要配置的东西,现在spring boot帮我们做了
整合JAVAEE和解决方案都在这个spring-boot-autoconfiguration-xxx.jar
这个包下
它会把所有需要导入的组件以类名的方式返回,这些组件就会被添加到容器
容器中也存在着非常多的xxxAutoConfiguration
的文件,就是这些文件给这个容器中导入了这个场景所需要的所有组件,并自动配置
# 启动方法
Run方法
- 推断应用的类型是普通的项目还是Web项目
- 查找并加载所有可用初始化器 , 设置到initializers属性中
- 找出所有的应用程序监听器,设置到listeners属性中
- 推断并设置main方法的定义类,找到运行的主类
# Spring Boot配置文件
我们看到Spring Boot的配置文件resource/application.properties
到底能配置什么东西
讲东西要讲原理,官方的配置太多了,要了解原理一通百通
- 可以删掉
application.properties
,因为官方不建议使用properties
- 建立
application.yaml
,因为官方支持yaml
并且建议使用yaml
并且yaml
功能易学强大,用的人多
注意,
applicatioin
这个名称是固定的,在配置中可以看到:我们要么使用
application.prperties
要么使用
application.yaml
# yaml
# yaml
是什么
yaml
不是一种标记语言的,但是它同时也是一种标记语言,以数据为中心的
可以做配置
# yaml
的语法与properties
做对比
yaml
的语法是key: value
(注意空格)properties
的语法是key=value
注意,
yaml
对空格的严格十分高
# 给实体类赋值
除此之外,
yaml
一个更强大的地方为还可以注入到配置类中!
首先来两个pojo
Dog
@Component
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Dog {
private String name;
private Integer age;
}
Person
@Component
@Data
@AllArgsConstructor
@NoArgsConstructor
@ConfigurationProperties(prefix = "person") //这个就是那个赋值的注解,直接关联yaml中的person
public class Person {
private String name;
private Integer age;
private Boolean happy;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
}
下面来给Person赋值:
application.yaml
,将会被@ConfigurationProperties
注解关联到
person:
name: bean
age: 3
happy: false
birth: 2020/2/19
maps: {k1: v1,k2: v2}
list:
- code
- music
- girl
dog:
name: wang
age: 3
- 测试
@SpringBootTest
class SpringbootprojectApplicationTests {
@Autowired
private Person person;
@Test
void contextLoads() {
System.out.println(person);
}
}
- 结果
Person{name='bean', age=3, happy=false, birth=Wed Feb 19 00:00:00 CST 2020, maps={k1=v1, k2=v2}, lists=[code, music, girl], dog=Dog{name='wang', age=3}}
虽然在上面已经看到了,但是还是要再说一遍:
通过
application.yaml
可以配置各种配置,其中就包括给pojo
赋值通过注解
@ConfigurationProperties(prefix = "")
来指定配置,将其关联起来
如图所示,关联起来了
但是我们还看见了一个提示框,忽略也可以,但是不忽略的话就去它的链接,去那里找到一句话加上就可以了
它让放,你就放,放完就没了
# 松散绑定
随便在application.yml中的任意一个值时,都可以被识别到,只需要使用@Value注解即可
# 配置文件
# 配置文件的路径
在官网上我们可以找到,配制文件可以在这么几个地方:
file:./config
file:./
classpath:/config/
classpath:/
上面的file
就是我们总的项目路径
springbootproject
- application.yaml
- config
- application.yaml
- src
- resource/java
- application.yaml
- config
- application.yaml
- resource/java
# 优先级
通过测试,我们看到优先级是:
file:./config
file:./
classpath:/config/
classpath:/
也就是说,默认的给我们排序的优先级是最低的...
# 多套环境自由切换
# 多文件切换的方式
我们可以使用优先级覆盖的方式,但是这种方法太low了,我们要自助切换
首先我们来认清几个文件名字:
- application.yaml:默认环境
- application-dev.yaml:开发环境
- application-test.yaml:测试环境
我们可以在默认环境中使用spring.profiles.active=xxx
来切换环境
其中值只写application-xxx后面的xxx即可,比如
spring:
profiles:
active: dev
# 一个文件的方式
yaml
还有一个重大突破,就是可以把多套环境放在一个文件中,而不需要必须像properties
一样放在不同的文件中
使用---
来进行环境的分割
- application.yaml
## 环境切换,这里是默认配置
## 使用spring.profiles.active来激活某个版本
## 不激活版本就是默认配置
server:
port: 8080
spring:
profiles:
active: dev
---
## 通过---来进行配置的分割
## 首先设置配置
## 然后通过spring.profiles来给此配置命名
server:
port: 8081
spring:
profiles: dev
---
## 通过---来进行配置的分割
## 首先设置配置
## 然后通过spring.profiles来给此配置命名
server:
port: 8082
spring:
profiles: test
# JSR303校验
spring boot中可以使用校验,来验证这个数据是什么类型,比如:email,phone等等
spring boot他有一个注解叫做@Validated
数据校验,举个例子:
下面这里有很多注解:
尤其注意这个符合指定的正则表达式,这个可以代替任何的其他的注解
# 自动配置原理再讲解
看过配置之后,我们就想明白:到底还能配置些什么?
# 原理
首先我们在上次原理初探的时候已经看过了一些源码,最后的结论是一个文件:
spring-boot-autoconfigure-2.2.4.RELEASE.jar\META-INF\spring.factories
我们知道这是一个核心的自动装配的文件,所有的东西都在这里配好了
在:## Auto Configure
一栏中,我们可以看到许多:xxxAutoConfiguration
,很明显,这些东西都是自动装配的组件
我们能够配置的东西和这些自动装配的组件有很强大的联系,我们随便点开来看,就发现这里面有非常明显的套路性
它一定会存在一个xxxAutoConfiguration
,这个xxxAutoConfiguration
一定会装配一个xxxpropeties
,这个xxxAutoConfiguration
文件一定会和配置绑定,所以我们才能够使用
比如,随便在spring.factories
点开一个xxxAutoConfiguration
,这次选中的是:org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
发现几个注解,其中有两个重要的:
@Configuration(proxyBeanMethods = false) //声明这是一个配置类
@ConditionalOnClass(RedisOperations.class)//当满足这里面的条件时才会启动这个类
@EnableConfigurationProperties(RedisProperties.class) //当里面的一个注解生效,它才会生效
那么根据提示,我们进入到RedisProperties.class
,发现一个注解:
@ConfigurationProperties(prefix = "spring.redis")
这个注解我们刚刚学过,就是在学习yaml
的时候使用yaml
直接向配置中绑定并注入数据
那么我们明白了,我们就可以使用spring.redis
来对RedisProperties.class
进行配置了,我们来看看这个类中有什么属性
@ConfigurationProperties(prefix = "spring.redis")
public class RedisProperties {
private int database = 0;
private String url;
private String host = "localhost";
private String password;
private int port = 6379;
private boolean ssl;
private Duration timeout;
private String clientName;
private Sentinel sentinel;
private Cluster cluster;
private final Jedis jedis = new Jedis();
private final Lettuce lettuce = new Lettuce();
}
public static class Cluster {
private List<String> nodes;
private Integer maxRedirects;
}
public static class Sentinel {
private String master;
private List<String> nodes;
}
public static class Jedis {
private Pool pool;
}
public static class Lettuce {
private Duration shutdownTimeout = Duration.ofMillis(100);
private Pool pool;
}
所以事情就很明显了,我们在application.yaml
中随便输入一个属性来设置,比如<font style="background-color:transparent;">Sentinel.master</font>
,因为绑定的是<font style="background-color:transparent;">spring.redis</font>
,所以:
spring:
redis:
sentinel:
master:
所以结论是:
对于任何的配置,一定会存在一个
xxxAutoConfiguration
,这个xxxAutoConfiguration
一定会装配一个xxxpropeties
,这个xxxAutoConfiguration
文件一定会和配置绑定,所以我们才能够使用
# 自动装配的精髓
SpringBoot
启动会加载大量的自动配置类- 我们看我们需要的功能有没有在
SpringBoot
默认写好的自动配置类当中; - 我们再来看这个自动配置类中到底配置了哪些组件;(只要我们要用的组件存在在其中,我们就不需要再手动配置了)
- 给容器中自动配置类添加组件的时候,会从properties类中获取某些属性。我们只需要在配置文件中指定这些属性的值即可;
xxxxAutoConfigurartion
:自动配置类;给容器中添加组件
xxxxProperties
:封装配置文件中相关属性;
# 细节问题
@Conditional派生注解(Spring注解版原生的@Conditional作用)
作用:必须是@Conditional指定的条件成立,才给容器中添加组件,配置配里面的所有内容才生效;
我们怎么知道哪些自动配置类生效;我们可以通过启用 debug=true属性;来让控制台打印自动配置报告,这样我们就可以很方便的知道哪些自动配置类生效;
#开启springboot的调试类
debug=true
Positive matches:(自动配置类启用的:正匹配)
Negative matches:(没有启动,没有匹配成功的自动配置类:负匹配)
Unconditional classes: (没有条件的类)
# 自己写一个Starter
1、首先是一个SpringBoot项目随便你怎么写
2、在Resources下面新建WEB-INF文件夹,在里面新建一个 _spring.factories_文件
3、写一个Configuration,里面写一个我们扫描的位置
@Configuration
@ComponentScan("com.howling")
public class MyConfiguration {}
4、在spring.factories里面写内容,写入多个key-value形式的
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.howling.starter.MyConfiguration
在这里面,key是固定的,value是你自己写的路径
5、在其他项目中引入
<dependency>
<groupId>com.howling</groupId>
<artifactId>howling-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>