☰
springboot启动过程笔记
2026/10/15 21:28:36 网站建设 项目流程

springboot启动过程笔记(2.7.7为例)
面试被问到了,答不上来,做个笔记。

一、概括

1、启动代码概括: 入口 → 创建SpringApplication → 运行run方法
2、核心步骤: 创建默认上下文->加载环境->上下文设置参数->刷新上下文->成功后的通知

二、入口代码

@SpringBootApplicationpublicclassSpringbootApplication{publicstaticvoidmain(String[]args){SpringApplication.run(SpringbootApplication.class,args);}}

通过SpringApplication.run启动。点进run方法

publicstaticConfigurableApplicationContextrun(Class<?>primarySource,String...args){returnrun(newClass<?>[]{primarySource},args);}/** * Static helper that can be used to run a {@link SpringApplication} from the * specified sources using default settings and user supplied arguments. * @param primarySources the primary sources to load * @param args the application arguments (usually passed from a Java main method) * @return the running {@link ApplicationContext} */publicstaticConfigurableApplicationContextrun(Class<?>[]primarySources,String[]args){returnnewSpringApplication(primarySources).run(args);}

可以看到经过一层包装后,调用了new SpringApplication(primarySources).run(args);
分成创建SpringApplication与启动run方法两个部分。下面一一介绍。

三、创建SpringApplication

代码

publicSpringApplication(Class<?>...primarySources){this(null,primarySources);}publicSpringApplication(ResourceLoaderresourceLoader,Class<?>...primarySources){this.resourceLoader=resourceLoader;Assert.notNull(primarySources,"PrimarySources must not be null");this.primarySources=newLinkedHashSet<>(Arrays.asList(primarySources));this.webApplicationType=WebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializers=newArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClass=deduceMainApplicationClass();}

加载了很多配置,监听器。感觉是启动前的准备工作。

功能简介

resourceLoader(资源加载器)

资源加载器决定文件加载方式,默认null

primarySources(启动类的类名)

启动类的类名

webApplicationType (应用类型)

staticWebApplicationTypededuceFromClasspath(){if(ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS,null)&&!ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS,null)&&!ClassUtils.isPresent(JERSEY_INDICATOR_CLASS,null)){returnWebApplicationType.REACTIVE;}for(StringclassName:SERVLET_INDICATOR_CLASSES){if(!ClassUtils.isPresent(className,null)){returnWebApplicationType.NONE;}}returnWebApplicationType.SERVLET;}

根据相关类是否存在来推断应用类型,默认SERVLET
三种web类型对比如下

  • REACTIVE 非阻塞响应,并发情况效率更高
  • NONE 不包含web部分,启动快,内存,cpu占用更小
  • SERVLET 最常见的

bootstrapRegistryInitializers

初始化阶段会调用

默认null

关键代码

private<T>Collection<T>getSpringFactoriesInstances(Class<T>type,Class<?>[]parameterTypes,Object...args){ClassLoaderclassLoader=getClassLoader();// Use names and ensure unique to protect against duplicatesSet<String>names=newLinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type,classLoader));List<T>instances=createSpringFactoriesInstances(type,parameterTypes,classLoader,args,names);AnnotationAwareOrderComparator.sort(instances);returninstances;}publicstaticList<String>loadFactoryNames(Class<?>factoryType,@NullableClassLoaderclassLoader){ClassLoaderclassLoaderToUse=classLoader;if(classLoaderToUse==null){classLoaderToUse=SpringFactoriesLoader.class.getClassLoader();}StringfactoryTypeName=factoryType.getName();returnloadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName,Collections.emptyList());}

加载spring.factories文件下,key为org.springframework.context.ApplicationContextInitializer的所有类

ApplicationContextInitializer

会在上下文创建完成时,执行
默认有如下实现类
0 = {DelegatingApplicationContextInitializer@1579}
1 = {SharedMetadataReaderFactoryContextInitializer@1580}
2 = {ContextIdApplicationContextInitializer@1581}
3 = {ConfigurationWarningsApplicationContextInitializer@1582}
4 = {RSocketPortInfoApplicationContextInitializer@1583}
5 = {ServerPortInfoApplicationContextInitializer@1584}
6 = {ConditionEvaluationReportLoggingListener@1585}

setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));

getSpringFactoriesInstances方法同上,获取所有ApplicationContextInitializer

ApplicationListener

贯穿整个创建周期根据type决定是否执行
默认如下实现类
0 = {EnvironmentPostProcessorApplicationListener@1677}
1 = {AnsiOutputApplicationListener@1678}
2 = {LoggingApplicationListener@1679}
3 = {BackgroundPreinitializer@1680}
4 = {DelegatingApplicationListener@1681}
5 = {ParentContextCloserApplicationListener@1682}
6 = {ClearCachesApplicationListener@1683}
7 = {FileEncodingApplicationListener@1684}
也是通过getSpringFactoriesInstances方法获取

setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));

mainApplicationClass(主启动类)

推断出当前应用的主启动类

privateClass<?>deduceMainApplicationClass(){try{StackTraceElement[]stackTrace=newRuntimeException().getStackTrace();for(StackTraceElementstackTraceElement:stackTrace){if("main".equals(stackTraceElement.getMethodName())){returnClass.forName(stackTraceElement.getClassName());}}}catch(ClassNotFoundExceptionex){// Swallow and continue}returnnull;}

遍历当前线程的调用栈,找到第一个名为 main 的方法,然后返回它所在的类。

四、run方法分析

代码

publicConfigurableApplicationContextrun(String...args){// 1、打印耗时longstartTime=System.nanoTime();// 2、创建默认上下文DefaultBootstrapContextbootstrapContext=createBootstrapContext();ConfigurableApplicationContextcontext=null;// 3、设置Headless模式configureHeadlessProperty();// 4、获取SpringApplicationRunListeners 监听器集合SpringApplicationRunListenerslisteners=getRunListeners(args);// 5、启用监听器,触发其‘spring.boot.application.starting"’事件listeners.starting(bootstrapContext,this.mainApplicationClass);try{// 6、入参args转成ApplicationArgumentsApplicationArgumentsapplicationArguments=newDefaultApplicationArguments(args);// 7、创建环境,并触发监听器‘spring.boot.application.environment-prepared’事件ConfigurableEnvironmentenvironment=prepareEnvironment(listeners,bootstrapContext,applicationArguments);// 8、配置是否需要忽略的beanconfigureIgnoreBeanInfo(environment);// 9、打印bannerBannerprintedBanner=printBanner(environment);// 10、 创建真正的应用上下文context=createApplicationContext();// 11、注册启动检测器context.setApplicationStartup(this.applicationStartup);// 12 上下文添加参数,并触发监听器 spring.boot.application.environment-prepared 与spring.boot.application.context-loaded事件prepareContext(bootstrapContext,context,environment,listeners,applicationArguments,printedBanner);// 13 刷新应用上下文,创建bean对象refreshContext(context);// 14、刷新上下文之后的操作,里面啥也afterRefresh(context,applicationArguments);// 15、计算耗时DurationtimeTakenToStartup=Duration.ofNanos(System.nanoTime()-startTime);// 16、打印启动完成日志if(this.logStartupInfo){newStartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(),timeTakenToStartup);}// 17、触发监听器启动完成日志 spring.boot.application.context-preparedlisteners.started(context,timeTakenToStartup);// 18 调用所有实现了 ApplicationRunner 和 CommandLineRunner 接口的 BeancallRunners(context,applicationArguments);}catch(Throwableex){// 19、异常处理handleRunFailure(context,ex,listeners);thrownewIllegalStateException(ex);}try{// 20、计算从应用启动开始到所有 Runner 执行完成的总耗时,并通知监听器“应用已完全就绪”,发布 ApplicationReadyEventDurationtimeTakenToReady=Duration.ofNanos(System.nanoTime()-startTime);listeners.ready(context,timeTakenToReady);}catch(Throwableex){// 19、异常处理handleRunFailure(context,ex,null);thrownewIllegalStateException(ex);}returncontext;}

光看备注还是不清楚,补充个图


简单来说就是,创建默认上下文->加载环境->上下文设置参数->刷新上下文->成功后的通知。具体内容有空再一一记录。

四、核心事件介绍

介绍创建默认上下文->加载环境->上下文设置参数->刷新上下文->成功后的通知

4.1、创建默认上下文 createBootstrapContext

privateDefaultBootstrapContextcreateBootstrapContext(){DefaultBootstrapContextbootstrapContext=newDefaultBootstrapContext();this.bootstrapRegistryInitializers.forEach((initializer)->initializer.initialize(bootstrapContext));returnbootstrapContext;}

直接new一个DefaultBootstrapContext,然后遍历bootstrapRegistryInitializers,执行对应方法。没啥好讲的。

4.2、加载环境 prepareEnvironment

privateConfigurableEnvironmentprepareEnvironment(SpringApplicationRunListenerslisteners,DefaultBootstrapContextbootstrapContext,ApplicationArgumentsapplicationArguments){// 创建环境 ConfigurableEnvironmentConfigurableEnvironmentenvironment=this.getOrCreateEnvironment();this.configureEnvironment(environment,applicationArguments.getSourceArgs());ConfigurationPropertySources.attach(environment);listeners.environmentPrepared(bootstrapContext,environment);DefaultPropertiesPropertySource.moveToEnd(environment);Assert.state(!environment.containsProperty("spring.main.environment-prefix"),"Environment prefix cannot be set via properties.");this.bindToSpringApplication(environment);if(!this.isCustomEnvironment){EnvironmentConverterenvironmentConverter=newEnvironmentConverter(this.getClassLoader());environment=environmentConverter.convertEnvironmentIfNecessary(environment,this.deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);returnenvironment;}

4.2.1 创建环境 getOrCreateEnvironment

privateConfigurableEnvironmentgetOrCreateEnvironment(){if(this.environment!=null){returnthis.environment;}else{ConfigurableEnvironmentenvironment=this.applicationContextFactory.createEnvironment(this.webApplicationType);if(environment==null&&this.applicationContextFactory!=ApplicationContextFactory.DEFAULT){environment=ApplicationContextFactory.DEFAULT.createEnvironment(this.webApplicationType);}return(ConfigurableEnvironment)(environment!=null?environment:newApplicationEnvironment());}}

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询