今天我们来看一下Springboot的启动过程
准备阶段
SpringApplication.run静态方法是最常用的启动入口,我们就从这个方法开始
WebApplicationType.deduceFromClasspath();将识别出应用的类型,传统的Servlet web应用、Reactor web应用、非web应用
第2步则是加载BootstrapRegistryInitializer、ApplicationContextInitializer、ApplicationListener
他们都是通过扫描classpath下各个jar包META-INF/spring.factories文件中所配置的类名称加载和过滤得到的
因此我们自定义配置的也会被加载进来
第3步deduceMainApplicationClass();因则是使用栈信息推断出启动类,即栈信息中最近的main方法所在的类,一般我们命名都是XxxApplication的类
接下来开始执行成员方法run
我们先来看run方法中的getRunListeners(args);
它将从META-INF/spring.factories加载出所有的SpringApplicationRunListener它并封装到SpringApplicationRunListeners
Spring内置的listeners有EventPublishingRunListener
这个Listener是用来向所有ApplicationListener发送各种ApplicationEvent的,例如ApplicationStartingEvent
我们继续看run方法中的listeners.starting(bootstrapContext, this.mainApplicationClass);
这里会触发所有SpringApplicationRunListener的starting方法,其中EventPublishingRunListener的starting就会发送ApplicationStartingEvent
准备Environment
我们继续看run方法中的ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
这里第1步将根据webApplicationType创建对应的ConfigurableEnvironment
ServletWebServerApplicationContextFactory创建ApplicationServletEnvironment
ReactiveWebServerApplicationContextFactory创建ApplicationReactiveWebEnvironment
第2步则触发所有SpringApplicationRunListener的environmentPrepared,其中包括EventPublishingRunListener发送ApplicationEnvironmentPreparedEvent
我们继续看run方法中的context = createApplicationContext();
这里同样将根据webApplicationType创建对应的ConfigurableApplicationContext
ServletWebServerApplicationContextFactory创建ServletWebServerApplicationContext
ReactiveWebServerApplicationContextFactory创建ReactiveWebServerApplicationContext
准备Context
我们继续看run方法中的prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
applyInitializers将会触发所有ApplicationContextInitializer. initialize(context);
listeners.contextPrepared(context); 将会触发所有SpringApplicationRunListener的contextPrepared,其中包括EventPublishingRunListener发送ApplicationContextInitializedEvent
bootstrapContext.close(context); 将会向所有ApplicationListener发送BootstrapContextClosedEvent
context.addBeanFactoryPostProcessor则向context增加BeanFactoryPostProcessor
最后listeners.contextLoaded(context); 将会触发所有SpringApplicationRunListener的contextLoaded,其中包括EventPublishingRunListener发送ApplicationPreparedEvent
我们继续看run方法中的refreshContext(context);
这里把context注册到优雅停机Hook
接下来就进入到spring-context范畴的启动过程了
我们来看refresh方法中的prepareBeanFactory(beanFactory);
这里给beanFactory加入了几个BeanPostProcessor
ApplicationContextAwareProcessor将会给实现各种Aware接口的bean触发相应的setXxx方法,例如applicationContextAware.setApplicationContext
ApplicationListenerDetector将会把ApplicationListener添加给applicationContext
我们来看refresh方法中的postProcessBeanFactory(beanFactory);
这里如果context类型是ServletWebServerApplicationContext就会执行以下步骤
这里给beanFactory加入了类型是WebApplicationContextServletContextAwareProcessor的BeanPostProcessor
WebApplicationContextServletContextAwareProcessor将会给实现ServletContextAware、ServletConfigAware接口的bean触发相应的setXxx方法
我们来看refresh方法中的invokeBeanFactoryPostProcessors(beanFactory);
这里面将按PriorityOrdered、@Order顺序触发所有的BeanFactoryPostProcessor和BeanDefinitionRegistryPostProcessor
部分代码
我们来看refresh方法中的registerBeanPostProcessors(beanFactory);
这里面将按PriorityOrdered、@Order顺序向beanFactory添加BeanPostProcessor
部分代码
启动Server
我们来看refresh方法中的onRefresh();
这里ServletWebServerApplicationContext、ReactiveWebServerApplicationContext有各自的实现,而非web则是默认的空实现
ServletWebServerApplicationContext的实现
看createWebServer(里面创建server之后将会启动起来,例如tomcat的 this.tomcat.start();)
这里的ServletWebServerFactory有多种实现
使用哪一种是由依赖的servlet容器jar包决定的,看ServletWebServerFactoryConfiguration的代码就可以知道
在这里已经根据环境决定了ServletWebServerFactory
再来看ReactiveWebServerApplicationContext的实现
这里的ReactiveWebServerFactory有多种实现
使用哪一种是由依赖的jar包决定的,看ReactiveWebServerFactoryConfiguration的代码就可以知道
在这里已经根据环境决定了ReactiveWebServerFactory
另外在上面this.serverManager = new WebServerManager(this, webServerFactory, this::getHttpHandler, lazyInit); 时内部就创建了WebServer
初始化Bean
我们来看refresh方法中的finishBeanFactoryInitialization(beanFactory);
这里主要是初始化初始化所有non-lazy singleton beans和触发所有SmartInitializingSingleton的afterSingletonsInstantiated
需要特别说明的是getBean(beanName); 的深层处将会触发BeanPostProcessor的postProcessBeforeInitialization方法和postProcessAfterInitialization方法
这个过程在AbstractAutowireCapableBeanFactory属于spring-beans范畴,来看中间的invokeInitMethods(beanName, wrappedBean, mbd);
如果bean是实现了InitializingBean则将执行afterPropertiesSet,如果具有init方法 或 方法具有注解@ PostConstruct则将执行对应的初始化方法
我们来看refresh方法中的finishRefresh();
这里getLifecycleProcessor().onRefresh();将触发所有Lifecycle这bean的start方法
Note:我们通过
Springcloud 服务注册与发现是怎么工作的_springcloud服务注册和发现如何实现的_icodegarden的博客-CSDN博客
篇章知道springboot启动阶段的服务注册是在Lifecycle的start中触发的,因此首次注册服务发生在WebServer启动之后
publishEvent(new ContextRefreshedEvent(this)); 向所有ApplicationListener发送ContextRefreshedEvent
refresh方法到此结束主要流程
我们继续看run方法中的listeners.started(context, timeTakenToStartup);
这里会触发所有SpringApplicationRunListener的started方法,其中EventPublishingRunListener的started就会发送ApplicationStartedEvent和内容是LivenessState.CORRECT (liveness已正常)的AvailabilityChangeEvent(可用性变更时间)
我们继续看run方法中的callRunners(context, applicationArguments);
这里将触发所有ApplicationRunner和CommandLineRunner
我们继续看run方法中的listeners.ready(context, timeTakenToReady);
这里会触发所有SpringApplicationRunListener的ready方法,其中EventPublishingRunListener的ready就会发送ApplicationReadyEvent和内容是ReadinessState.ACCEPTING_TRAFFIC(readness已正常)的AvailabilityChangeEvent(可用性变更时间)
到此Springboot就启动完毕了
最后补充一点Springboot的变更,从Springboot3开始META-INF/spring.factories的org.springframework.boot.autoconfigure.EnableAutoConfiguration 部分变更为配置在META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports中