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

指定扫描哪些,自定义了两个扫描器TypeExcludeFilter、AutoConfigurationExcludeFilter

3. @EnableAutoConfiguration

@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})
public @interface EnableAutoConfiguration {}

3.1 @AutoConfigurationPackage

自动配置包,指定了默认的包规则

@Import({Registrar.class}) //给容器中导入一个组件
public @interface AutoConfigurationPackage {}

//利用Registrar给容器导入一系列组
//将指定的包下的所有组件导入进来,也就是MainApplication所在的包下所有组件

3.2 @Import({AutoConfigurationImportSelector.class})

1. 利用该方法 给容器中批量导入一些组件
AutoConfigurationImportSelector.AutoConfigurationEntry autoConfigurationEntry = this.getAutoConfigurationEntry(autoConfigurationMetadata, annotationMetadata);
2. 调用该方法获取到所有需要导入到容器中的配置类
List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);
3. 利用工厂加载
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(this.getSpringFactoriesLoaderFactoryClass(), this.getBeanClassLoader());
4. 得到所有组件(127个AutoConfiguration组件)
Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader)
5. 从META-INF/spring.factories位置来加载一个文件
默认扫描我们当前系统里面所有 META-INF/spring.factories 位置的文件
spring-boot-autoconfigure-2.5.0.jar包里面也有META-INF/spring.factories

spring-boot-autoconfigure-2.5.0.jar/META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器中加载的所有配置类

(二)按需开启自动配置项

虽然我们127个场景的所有自动配置启动的时候默认全部加载。

xxxxAutoConfiguration 按照条件装配规则(@Conditional),最终会按需配置

1. AOP自动装配类(@Conditional

@Configuration(proxyBeanMethods = false)
@ConditionalOnProperty(prefix = "spring.aop", name = "auto", havingValue = "true", matchIfMissing = true)
public class AopAutoConfiguration {
    @Configuration(proxyBeanMethods = false)
    @ConditionalOnClass(Advice.class)     //按需加载,有aspectj相关组件,才会加载该 AopAutoConfiguration!!!!!!!!!!!
    static class AspectJAutoProxyingConfiguration {
    }
}

2. DispatcherServlet自动装配类(@Conditional@AutoConfigureAfter,@EnableConfigurationProperties

@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
@Configuration(proxyBeanMethods = false)
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass(DispatcherServlet.class)
@AutoConfigureAfter(ServletWebServerFactoryAutoConfiguration.class) //在ServletWebServerFactoryAutoConfiguration配置类配置完成后,再来配置当前配置类
public class DispatcherServletAutoConfiguration {
    @Configuration(proxyBeanMethods = false)
    @Conditional(DefaultDispatcherServletCondition.class)
    @ConditionalOnClass(ServletRegistration.class)
    @EnableConfigurationProperties(WebMvcProperties.class)    // 这里会加载配置文件中 spring.mvc 相关配置参数
    protected static class DispatcherServletConfiguration {
    }
}
@ConfigurationProperties(prefix = "spring.mvc")
public class WebMvcProperties {}

3. HttpEncoding自动配置类(@Conditional、@ConfigurationProperties

@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(ServerProperties.class)
@ConditionalOnWebApplication(type = ConditionalOnWebApplication.Type.SERVLET)
@ConditionalOnClass(CharacterEncodingFilter.class)
@ConditionalOnProperty(prefix = "server.servlet.encoding", value = "enabled", matchIfMissing = true)
public class HttpEncodingAutoConfiguration {
}

@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
    /**
     * Server HTTP port.
     */
    private Integer port;

    /**
     * Network address to which the server should bind.
     */
    private InetAddress address;
}

3.1 SpringBoot会在底层配好所有的组件,但是如果用户自己配置了,以用户的优先

// 系统自带
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {
    CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
    filter.setEncoding(this.properties.getCharset().name());
    filter.setForceRequestEncoding(this.properties.shouldForce(Encoding.Type.REQUEST));
    filter.setForceResponseEncoding(this.properties.shouldForce(Encoding.Type.RESPONSE));
    return filter;
}

//用户不想用系统的,也可重写
@Bean
public CharacterEncodingFilter myFile() {
return }

总结:

  • SpringBoot先加载所有的自动配置类 xxxAutoConfiguration
  • 每个自动配置类按照条件进行生效,默认都会开启属性绑定,绑定配置文件指定的值,xxxProperties里面拿,xxxProperties和配置文件 进行绑定
  • 生效的配置类就会给容器中装配很多组件
  • 只要容器中有这些组件,相当于这些功能就有了
  • 只要用户有自己配置的,就以用户的优先
  • 定制化配置
    • 用户直接自己@Bean替换底层的组件
    • 用户去看这个组件是获取的配置文件什么值就去修改

从xxxxAutoConfiguration ---> 导入很多组件 ---> EnableConfigurationProperties ---> 组件从xxxProperties里面拿值 ----> 从application.properties配置文件中获取

 

二、SpringBoot启动过程

1. 创建SpringApplication

(1) 保存一些信息。

(2) 判定当前应用的类型。ClassUtils。Servlet

(3) 找bootstrappers;初始启动引导器(List<Bootstrapper>),getSpringFactoriesInstances()META-INF/spring.factories文件中找Bootstrapper

(4) 找ApplicationContextInitializer初始化器;getSpringFactoriesInstances()META-INF/spring.factories文件中找ApplicationContextInitializer

      List<ApplicationContextInitializer<?>> initializers

(5) 找ApplicationListener应用监听器;getSpringFactoriesInstances()META-INF/spring.factories文件中找ApplicationListener

(6) 找到主程序

2. 运行SpringApplication

(1) StopWatch

     记录应用的启动时间

(2) 创建引导上下文(Context环境)createBootstrapContext()

  • 获取所有之前 bootstrappers 挨个执行 intitialize() 来完成对引导启动器上下文环境设置
public interface Bootstrapper {

    /**
     * Initialize the given {@link BootstrapRegistry} with any required registrations.
     * @param registry the registry to initialize
     */
    void intitialize(BootstrapRegistry registry);

}

(3) 让当前应用进入headless模式,java.awt.headless

(4) 获取所有RunListener(运行监听器)【为了方便所有 Listener进行事件感知】

  • getSpringFactoriesInstances() META-INF/spring.factories文件中找SpringApplicationRunListener

(5) 遍历 SpringApplicationRunListener 调用listener.starting() 方法;【刚创建完上下文容器的基本信息,就调用starting,代表容器准备启动了!!!!!!!】

  • 相当于通知所有感兴趣系统正在启动过程的人,项目正在starting.

(6) 保存命令行参数: ApplicationArguments

(7) 准备环境 prepareEnvironment()

  • 返回或创建一个基础环境信息对象 StandardServletEnvironment
  • 配置环境信息对象。
    • 读取所有的配置源的配置属性值
  • 绑定环境信息
  • 监听器调用 listener.environmentPrepared();通知所有的监听器当前环境准备完成【环境信息准备完成后调用,代表环境信息准备完成了!!!!!!!】

(8) 创建IOC容器 createApplicationContext()

  • 根据项目类型(Servlet)创建容器
  • 当前会创建 AnnotationConfigServletWebServerApplicationContext

(9) 准备ApplicationContext IOC容器的基本信息 prepareContext()

  • 保存环境信息
  • IOC容器的后置处理流程
  • 应用初始化器, applyInitializers
    • 遍历所有的ApplicationContextInitializer,调用initialize() 来对ioc容器进行初始化扩展功能。
    • 遍历所有的调用 listener.contextPrepared()。EvenpublishRunListener 通知所有的监听器contextPrepared【IOC容器准备完成后调用可以开始注册组件、获取组件!!!!!!!】

  • 通知所有的监听器,调用 listener.contextLoaded(),通知所有监听器 contextLoaded;【IOC容器加载完成后调用!!!!!!!!!!!】

(10) 刷新 IOC容器  refreshContext()

创建容器中的所有组件(需要补充学习)

a. 初始化准备

b. 创建Bean工厂ConfigurableListableBeanFactory ,并获取Bean定义信息

c. 初始化Bean工厂prepareBeanFactory

d. 在bean实例化后创建之前调用BeanFactoryPostProcessors后置处理方法

e. 注册并实例化所有BeanPostProcessors

f. 国际化

g. 进行相关事件发布

h. OnRefresh() —— 创建内置的Servlet容器 SpringBoot Tomcat在这里启动

i. 注册应用监听器

j. 实例化 所有剩下的非懒加载的单例实例对象

 

(11) 容器刷新完成后工作 afterRefresh()

(12) StopWatch

  stopWath.stop();

(13) 所有监听器调用 listeners.started(context); 通知所有的监听器started【IOC容器开始启动调用这里容器已完成刷新,且已创建实例!!!!!!!】

(14) 调用所有的runners callRunners()

  • 获取容器中的ApplicationRunner
  • 获取容器中的CommandLineRunner
  • 获取所有runner并且按照@Order进行排序
  • 遍历所有的runner,调用run方法
  • 如果以上有异常
    • 调用Listener的falid

(15) 调用所有监听器的running方法 listeners.running(context); 通知所有的监听器running【IOC容器启动完成后调用这里容器已启动完成!!!!!!!】

  • running如果有问题,继续通知faild,调用所有Listener的faile, 通知所有的监听器faild

 

五大组件

1. ApplicationContextInitializer 初始化器

.initialize();

2. ApplicationListener 应用监听器

.onApplicationEvent()

3. SpringApplicationRunListener 运行监听器

.starting()

.environmentPrepared()

.contextPrepared()

.contextLoaded()

.started

.running

4. ApplicationRunner

.run()

5. CommandLineRunner

.run()

 

 

 

 

 

 刷新 IOC容器 refreshContext 创建容器中的所有组件(需要补充学习):

1. 初始化准备

2. 创建Bean工厂ConfigurableListableBeanFactory ,并获取Bean定义信息

3. 初始化Bean工厂prepareBeanFactory

4. 在bean实例化后创建之前调用BeanFactoryPostProcessors后置处理方法

5. 注册并实例化所有BeanPostProcessors

6. 国际化

7. 进行相关事件发布

8. OnRefresh() —— 创建内置的Servlet容器 SpringBoot Tomcat在这里启动

9. 注册应用监听器

10. 实例化 所有剩下的非懒加载的实例对象

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2022-03-18 16:34  yifanSJ  阅读(1147)  评论(0编辑  收藏  举报