注:本文总结来自B站尚硅谷SpringBoot2教程
视频:https://www.bilibili.com/video/BV19K4y1L7MT?p=87&spm_id_from=pageDriver
笔记:https://www.yuque.com/atguigu/springboot/tmvr0e
SpringBoot自动配置原理
引导加载自动配置类
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication{}
1、@SpringBootConfiguration
@Configuration。代表当前是一个配置类
2、@ComponentScan
指定扫描哪些,Spring注解;
3、@EnableAutoConfiguration
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {}
3.1、@AutoConfigurationPackage
自动配置包?指定了默认的包规则
@Import(AutoConfigurationPackages.Registrar.class) //给容器中导入一个组件
public @interface AutoConfigurationPackage {}
//利用Registrar给容器中导入一系列组件
//将指定的一个包下的所有组件导入进来?MainApplication 所在包下。
-
利用Registrar给容器中导入一系列组件
-
将指定的一个包下的所有组件导入进来?MainApplication 所在包下
AutoConfigurationPackages.Registrar.class类
3.2、@Import(AutoConfigurationImportSelector
.class)
1、利用getAutoConfigurationEntry(annotationMetadata)
;给容器中批量导入一些组件
2、调用List configurations = getCandidateConfigurations(annotationMetadata, attributes)
获取到所有需要导入到容器中的配置类
3、利用工厂加载 Map<String, List> loadSpringFactories
(@Nullable ClassLoader classLoader);得到所有的组件
4、从META-INF/spring.factories
位置来加载一个文件。
默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件
spring-boot-autoconfigure-2.3.4.RELEASE.jar包里面也有META-INF/spring.factories
AutoConfigurationImportSelector类
configurations信息
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类
spring-boot-autoconfigure-2.3.4.RELEASE.jar/META-INF/spring.factories
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,\
........................
等127个之多
spring-boot-autoconfigure-2.2.1.RELEASE.jar包里META-INF/spring.factories
3.2、按需开启自动配置项
- 虽然我们127个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
3.3、修改默认配置
@Bean
@ConditionalOnBean(MultipartResolver.class) //容器中有这个类型组件
@ConditionalOnMissingBean(name = DispatcherServlet.MULTIPART_RESOLVER_BEAN_NAME) //容器中没有这个名字 multipartResolver 的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
//SpringMVC multipartResolver。防止有些用户配置的文件上传解析器不符合规范
// Detect if the user has created a MultipartResolver but named it incorrectly
return resolver;
}
给容器中加入了文件上传解析器;
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
}
总结:
-
SpringBoot先加载所有的自动配置类 xxxxxAutoConfiguration
-
每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
-
生效的配置类就会给容器中装配很多组件
-
只要容器中有这些组件,相当于这些功能就有了
-
定制化配置
-
用户直接自己@Bean替换底层的组件
-
用户去看这个组件是获取的配置文件什么值就去修改。
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 ----> application.properties
3.4、最佳实践
-
引入场景依赖
-
查看自动配置了哪些(选做)
-
自己分析,引入场景对应的自动配置一般都生效了
-
配置文件中debug=true开启自动配置报告。Negative(不生效)\Positive(生效)
-
是否需要修改
-
参照文档修改配置项
-
自己分析。xxxxProperties绑定了配置文件的哪些。
-
自定义加入或者替换组件
-
@Bean、@Component。。。
-
自定义器 XXXXXCustomizer;
-
…
SpringBoot启动过程
详情:https://www.yuque.com/atguigu/springboot/tmvr0e#B7hoA
-
创建 SpringApplication
-
保存一些信息。
-
判定当前应用的类型。ClassUtils。Servlet
-
bootstrappers**:初始启动引导器(List):去spring.factories文件中找** org.springframework.boot.Bootstrapper
-
找 ApplicationContextInitializer;去spring.factories****找 ApplicationContextInitializer
-
List<ApplicationContextInitializer<?>> initializers
-
找 ApplicationListener ;应用监听器。去spring.factories****找 ApplicationListener
-
List<ApplicationListener<?>> listeners
-
运行 SpringApplication
-
StopWatch
-
记录应用的启动时间
-
**创建引导上下文(Context环境)**createBootstrapContext()
-
获取到所有之前的 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
-
让当前应用进入headless模式。java.awt.headless
-
获取所有 RunListener**(运行监听器)【为了方便所有Listener进行事件感知】**
-
getSpringFactoriesInstances 去spring.factories****找 SpringApplicationRunListener.
-
遍历 SpringApplicationRunListener 调用 starting 方法;
-
相当于通知所有感兴趣系统正在启动过程的人,项目正在 starting。
-
保存命令行参数;ApplicationArguments
-
准备环境 prepareEnvironment();
-
返回或者创建基础环境信息对象。StandardServletEnvironment
-
配置环境信息对象。
-
读取所有的配置源的配置属性值。
-
绑定环境信息
-
监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成
-
创建IOC容器(createApplicationContext())
-
根据项目类型(Servlet)创建容器,
-
当前会创建 AnnotationConfigServletWebServerApplicationContext
-
准备ApplicationContext IOC容器的基本信息 prepareContext()
-
保存环境信息
-
IOC容器的后置处理流程。
-
应用初始化器;applyInitializers;
-
遍历所有的 ApplicationContextInitializer 。调用 initialize.。来对ioc容器进行初始化扩展功能
-
遍历所有的 listener 调用 contextPrepared。EventPublishRunListenr;通知所有的监听器****contextPrepared
-
所有的监听器 调用 contextLoaded。通知所有的监听器 contextLoaded;
-
**刷新IOC容器。**refreshContext
-
创建容器中的所有组件(Spring注解)
-
容器刷新完成后工作?afterRefresh
-
所有监听 器 调用 listeners.started(context); 通知所有的监听器 started
-
**调用所有runners;**callRunners()
-
获取容器中的 ApplicationRunner
-
获取容器中的 CommandLineRunner
-
合并所有runner并且按照@Order进行排序
-
遍历所有的runner。调用 run 方法
-
如果以上有异常,
-
调用Listener 的 failed
-
调用所有监听器的 running 方法 listeners.running(context); 通知所有的监听器 running
-
**running如果有问题。继续通知 failed 。**调用所有 Listener 的 **failed;**通知所有的监听器 failed