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.resourceLoaderresourceLoader;Assert.notNull(primarySources,PrimarySources must not be null);this.primarySourcesnewLinkedHashSet(Arrays.asList(primarySources));this.webApplicationTypeWebApplicationType.deduceFromClasspath();this.bootstrapRegistryInitializersnewArrayList(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));this.mainApplicationClassdeduceMainApplicationClass();}加载了很多配置监听器。感觉是启动前的准备工作。功能简介resourceLoader资源加载器资源加载器决定文件加载方式默认nullprimarySources启动类的类名启动类的类名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关键代码privateTCollectionTgetSpringFactoriesInstances(ClassTtype,Class?[]parameterTypes,Object...args){ClassLoaderclassLoadergetClassLoader();// Use names and ensure unique to protect against duplicatesSetStringnamesnewLinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type,classLoader));ListTinstancescreateSpringFactoriesInstances(type,parameterTypes,classLoader,args,names);AnnotationAwareOrderComparator.sort(instances);returninstances;}publicstaticListStringloadFactoryNames(Class?factoryType,NullableClassLoaderclassLoader){ClassLoaderclassLoaderToUseclassLoader;if(classLoaderToUsenull){classLoaderToUseSpringFactoriesLoader.class.getClassLoader();}StringfactoryTypeNamefactoryType.getName();returnloadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName,Collections.emptyList());}加载spring.factories文件下key为org.springframework.context.ApplicationContextInitializer的所有类ApplicationContextInitializer会在上下文创建完成时执行默认有如下实现类0 {DelegatingApplicationContextInitializer1579}1 {SharedMetadataReaderFactoryContextInitializer1580}2 {ContextIdApplicationContextInitializer1581}3 {ConfigurationWarningsApplicationContextInitializer1582}4 {RSocketPortInfoApplicationContextInitializer1583}5 {ServerPortInfoApplicationContextInitializer1584}6 {ConditionEvaluationReportLoggingListener1585}setInitializers((Collection)getSpringFactoriesInstances(ApplicationContextInitializer.class));getSpringFactoriesInstances方法同上获取所有ApplicationContextInitializerApplicationListener贯穿整个创建周期根据type决定是否执行默认如下实现类0 {EnvironmentPostProcessorApplicationListener1677}1 {AnsiOutputApplicationListener1678}2 {LoggingApplicationListener1679}3 {BackgroundPreinitializer1680}4 {DelegatingApplicationListener1681}5 {ParentContextCloserApplicationListener1682}6 {ClearCachesApplicationListener1683}7 {FileEncodingApplicationListener1684}也是通过getSpringFactoriesInstances方法获取setListeners((Collection)getSpringFactoriesInstances(ApplicationListener.class));mainApplicationClass主启动类推断出当前应用的主启动类privateClass?deduceMainApplicationClass(){try{StackTraceElement[]stackTracenewRuntimeException().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、打印耗时longstartTimeSystem.nanoTime();// 2、创建默认上下文DefaultBootstrapContextbootstrapContextcreateBootstrapContext();ConfigurableApplicationContextcontextnull;// 3、设置Headless模式configureHeadlessProperty();// 4、获取SpringApplicationRunListeners 监听器集合SpringApplicationRunListenerslistenersgetRunListeners(args);// 5、启用监听器触发其‘spring.boot.application.starting’事件listeners.starting(bootstrapContext,this.mainApplicationClass);try{// 6、入参args转成ApplicationArgumentsApplicationArgumentsapplicationArgumentsnewDefaultApplicationArguments(args);// 7、创建环境并触发监听器‘spring.boot.application.environment-prepared’事件ConfigurableEnvironmentenvironmentprepareEnvironment(listeners,bootstrapContext,applicationArguments);// 8、配置是否需要忽略的beanconfigureIgnoreBeanInfo(environment);// 9、打印bannerBannerprintedBannerprintBanner(environment);// 10、 创建真正的应用上下文contextcreateApplicationContext();// 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、计算耗时DurationtimeTakenToStartupDuration.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 执行完成的总耗时并通知监听器“应用已完全就绪”发布 ApplicationReadyEventDurationtimeTakenToReadyDuration.ofNanos(System.nanoTime()-startTime);listeners.ready(context,timeTakenToReady);}catch(Throwableex){// 19、异常处理handleRunFailure(context,ex,null);thrownewIllegalStateException(ex);}returncontext;}光看备注还是不清楚补充个图简单来说就是创建默认上下文-加载环境-上下文设置参数-刷新上下文-成功后的通知。具体内容有空再一一记录。四、核心事件介绍介绍创建默认上下文-加载环境-上下文设置参数-刷新上下文-成功后的通知4.1、创建默认上下文 createBootstrapContextprivateDefaultBootstrapContextcreateBootstrapContext(){DefaultBootstrapContextbootstrapContextnewDefaultBootstrapContext();this.bootstrapRegistryInitializers.forEach((initializer)-initializer.initialize(bootstrapContext));returnbootstrapContext;}直接new一个DefaultBootstrapContext然后遍历bootstrapRegistryInitializers执行对应方法。没啥好讲的。4.2、加载环境 prepareEnvironmentprivateConfigurableEnvironmentprepareEnvironment(SpringApplicationRunListenerslisteners,DefaultBootstrapContextbootstrapContext,ApplicationArgumentsapplicationArguments){// 创建环境 ConfigurableEnvironmentConfigurableEnvironmentenvironmentthis.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){EnvironmentConverterenvironmentConverternewEnvironmentConverter(this.getClassLoader());environmentenvironmentConverter.convertEnvironmentIfNecessary(environment,this.deduceEnvironmentClass());}ConfigurationPropertySources.attach(environment);returnenvironment;}4.2.1 创建环境 getOrCreateEnvironmentprivateConfigurableEnvironmentgetOrCreateEnvironment(){if(this.environment!null){returnthis.environment;}else{ConfigurableEnvironmentenvironmentthis.applicationContextFactory.createEnvironment(this.webApplicationType);if(environmentnullthis.applicationContextFactory!ApplicationContextFactory.DEFAULT){environmentApplicationContextFactory.DEFAULT.createEnvironment(this.webApplicationType);}return(ConfigurableEnvironment)(environment!null?environment:newApplicationEnvironment());}}