闲来无事,串一下springboot3.0的启动流程,一己之见,可能有误。
1 启动入口
//启动方法,返回上下文对象,入参,配置类信息,启动参数,后续会new 一个SpringApplication对象执行run方法
SpringApplication.run(Application.class, args);
2 创建对象
//new SpringApplication对象
this.sources = new LinkedHashSet();
//打印banner的方法,控制台、日志、不打印
this.bannerMode = Mode.CONSOLE;
this.logStartupInfo = true;
this.addCommandLineProperties = true;
this.addConversionService = true;
this.headless = true;
this.registerShutdownHook = true; //应该是注册虚拟机关闭钩子
this.additionalProfiles = Collections.emptySet();
this.isCustomEnvironment = false;
this.lazyInitialization = false;
//默认的上下文工厂,后续会由此对象生成Reactive或Servlet上下文
this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
this.applicationStartup = ApplicationStartup.DEFAULT;
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet(Arrays.asList(primarySources));
//推断webApp类型,逻辑是先判断有没有REACTIVE的相关类文件,有的话则是REACTIVE,没有的话判断是否包含全部的servlet相关,全部包含则是SERVLET,否则返回NONE
this.webApplicationType = WebApplicationType.deduceFromClasspath();
//通过SpringFactoriesLoader.forDefaultResourceLocation(this.getClassLoader()).load(type, argumentResolver)读取META-INF/spring.factories下的类信息
//不清楚,可能是要在启动前做某些事
this.bootstrapRegistryInitializers = new ArrayList(this.getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
//设置上下文初始化
this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class));
//设置监听器
this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class));
//推断主类,通过当前程序的堆栈信息,通过是否包含"main"关键字进行判断
this.mainApplicationClass = this.deduceMainApplicationClass();
3 run方法
public ConfigurableApplicationContext run(String... args) {
long startTime = System.nanoTime();
//创建bootstrap上下文
DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
ConfigurableApplicationContext context = null;
this.configureHeadlessProperty();
//创建事件监听,由EventPublishingRunListener进行事件分发
//会从当前SpringApplication对象对象中,拿出所有的监听者信息,进行事件分发
SpringApplicationRunListeners listeners = this.getRunListeners(args);
//发布事件
listeners.starting(bootstrapContext, this.mainApplicationClass);
try {
//启动参数包装
ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
//创建环境,发布事件,
//如果是cloud,会走BootstrapApplicationListener的监听方法,通过SpringApplicationBuilder先创建一个SpringApplication对象,先走一遍流程
//由EnvironmentPostProcessorApplicationListener接收事件,找到对应的ConfigDataEnvironmentPostProcessor等处理器,进行环境信息填充
//这里有一个很实用的方法:Binder.get(environment).bind("spring.main", Bindable.ofInstance(this));
//大概意思就是,从环境中,绑定某些信息到当前对象,或者是一个List,Map等
ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments);
//打印banner,判断打印类型,从环境中读取banner配置信息,如果没有取默认值banner.txt,如果还没有,就取构造时传递的SpringApplication对象中的banner对象,如果对象为null,取默认值SpringBootBanner
Banner printedBanner = this.printBanner(environment);
//创建上下文对象,通过上文推断的webApp类型进行创建
context = this.createApplicationContext();
context.setApplicationStartup(this.applicationStartup);
//准备上下文,注册一些单例bean、处理器,把传入的配置类转化为bean定义信息加入上下文,供后续创建bean
this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
//刷新上下文,注册jvm虚拟机关闭钩子,可在关闭的时候发布关闭事件,执行销毁bean对象方法
this.refreshContext(context);
//完成刷新,什么也没做
this.afterRefresh(context, applicationArguments);
Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
if (this.logStartupInfo) {
(new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), timeTakenToStartup);
}
//发布事件
listeners.started(context, timeTakenToStartup);
//执行实现ApplicationRunner和CommandLineRunner的启动方法
this.callRunners(context, applicationArguments);
} catch (Throwable var12) {
if (var12 instanceof SpringApplication.AbandonedRunException) {
throw var12;
}
this.handleRunFailure(context, var12, listeners);
throw new IllegalStateException(var12);
}
try {
if (context.isRunning()) {
Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
listeners.ready(context, timeTakenToReady);
}
return context;
} catch (Throwable var11) {
if (var11 instanceof SpringApplication.AbandonedRunException) {
throw var11;
} else {
this.handleRunFailure(context, var11, (SpringApplicationRunListeners)null);
throw new IllegalStateException(var11);
}
}
}
4 刷新上下文
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
//准备刷新
this.prepareRefresh();
//获取beanFactory,实现类是DefaultListableBeanFactory
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
//准备beanFactory,这一步会添加处理器等
this.prepareBeanFactory(beanFactory);
try {
//beanFactory后置处理
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
//执行beanFactory的后置处理器
//这一步的逻辑有点绕,处理BeanDefinitionRegistry和BeanFactoryPostProcessor
//先执行BeanDefinitionRegistry,然后从beanFactory获取优先(有排序)的BeanDefinitionRegistry,再执行优先级较低、没有优先级的BeanDefinitionRegistry
//然后执行BeanFactoryPostProcessor,执行的逻辑同上
//在的SpringApplication对象的run方法的prepareContext方法的load方法中,创建BeanDefinitionLoader的构造方法中,添加了默认的处理器
//这一步的BeanFactoryPostProcessor对象,由SpringApplication对象的applyInitializers方法加入的
//如果有传入,则优先执行传入的处理器,然后从beanFactory里面获取处理器并执行
//这一步会解析生成BeanDefinition
//扫描启动类上的注解应该也是在这一步执行的,主要的核心逻辑应该在ConfigurationClassPostProcessor和ConfigurationClassParser类
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册bean的处理器,处理逻辑同上
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
//初始化MessageSource,暂不清楚
this.initMessageSource();
//初始化事件分发器
this.initApplicationEventMulticaster();
//刷新,这一步如果是webApp类型,会在这里创建webServer,比如说TomcatServletWebServerFactory
this.onRefresh();
//注册事件监听者
this.registerListeners();
//创建bean,通过getBean的方法进行创建
this.finishBeanFactoryInitialization(beanFactory);
//完成刷新,发布事件
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}