简历写了解熟悉SpringBoot?请说一说 SpringBoot 的启动流程

tech2026-04-03  1

springBoot启动流程分析:

springBoot启动流程主要分两步:

new SpringApplication()应用运行 SpringApplication()对象

进入run方法:

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return (new SpringApplication(primarySources)).run(args); }

new SpringApplication()应用

进入new SpringApplication(primarySources)

public SpringApplication(Class<?>... primarySources) { //传入一个null this((ResourceLoader)null, primarySources); } public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { this.sources = new LinkedHashSet(); this.bannerMode = Mode.CONSOLE; this.logStartupInfo = true; this.addCommandLineProperties = true; this.addConversionService = true; this.headless = true; this.registerShutdownHook = true; this.additionalProfiles = new HashSet(); this.isCustomEnvironment = false; this.lazyInitialization = false; //初始化一个空的resourceLoader this.resourceLoader = resourceLoader; //断言primaySources 是否为空 Assert.notNull(primarySources, "PrimarySources must not be null"); //初始化主要加载资源类,并去重 this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); //判断web应用类型 NONE(非web项目),SERVLET(web项目),REACTIVE(响应式web项目); this.webApplicationType = WebApplicationType.deduceFromClasspath(); //设置应用上下文 初始化器 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //设置监听器 this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //推断主入口类 this.mainApplicationClass = this.deduceMainApplicationClass(); }

关键点:设置应用上下文初始化器、设置监听器

其两者做的事情是一样的,我们跟一下 this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); 源码。

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) { return this.getSpringFactoriesInstances(type, new Class[0]); } private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = this.getClassLoader(); //载入所有的ApplicationContextInitializer的类全限定名 Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader)); //使用反射将所有的ApplicationContextInitializer实例化 List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); AnnotationAwareOrderComparator.sort(instances); return instances; }

关键点:载入所有的ApplicationContextInitializer的类全限定名

public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) { String factoryTypeName = factoryType.getName(); //取出所有 factoryTypeName(这里指ApplicationContextInitializer)所有类的全限定名 return (List)loadSpringFactories(classLoader).getOrDefault(factoryTypeName, Collections.emptyList()); } /** * 解析出所有 META-INF/spring.factories 文件的属性返回 **/ private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) { //先从缓存取 MultiValueMap<String, String> result = (MultiValueMap)cache.get(classLoader); if (result != null) { return result; } else { try { //取出所有 META-INF/spring.factories 文件路径 Enumeration<URL> urls = classLoader != null ? classLoader.getResources("META-INF/spring.factories") : ClassLoader.getSystemResources("META-INF/spring.factories"); LinkedMultiValueMap result = new LinkedMultiValueMap(); while(urls.hasMoreElements()) { URL url = (URL)urls.nextElement(); UrlResource resource = new UrlResource(url); //转为 Properties 对象 Properties properties = PropertiesLoaderUtils.loadProperties(resource); Iterator var6 = properties.entrySet().iterator(); //解析 Properties while(var6.hasNext()) { Entry<?, ?> entry = (Entry)var6.next(); String factoryTypeName = ((String)entry.getKey()).trim(); String[] var9 = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); int var10 = var9.length; for(int var11 = 0; var11 < var10; ++var11) { String factoryImplementationName = var9[var11]; result.add(factoryTypeName, factoryImplementationName.trim()); } } } cache.put(classLoader, result); return result; } catch (IOException var13) { throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var13); } } }

再看一下META-INF/spring.factories文件:

spring是在所有你加载的 jar 包中找到需要的 ApplicationContextInitializer 进行动态配置,只要你用到了特定的 maven 包,初始化时就会找到这个包下的 META-INF/spring.factories 中需要的类进行实例化bean,你就可以用了,不需要任何配置。

运行 SpringApplication()对象

public ConfigurableApplicationContext run(String... args) { //开启启动计时器,项目启动完会打印执行时间出来 StopWatch stopWatch = new StopWatch(); stopWatch.start(); ConfigurableApplicationContext context = null; Collection<SpringBootExceptionReporter> exceptionReporters = new ArrayList(); this.configureHeadlessProperty(); //获取SpringApplicationRunListener并启动监听器 SpringApplicationRunListeners listeners = this.getRunListeners(args); listeners.starting(); Collection exceptionReporters; try { ApplicationArguments applicationArguments = new DefaultApplicationArguments(args); //环境变量的加载 环境变量包括system environment、classpath environment和用户自己加的application.properties ConfigurableEnvironment environment = this.prepareEnvironment(listeners, applicationArguments); this.configureIgnoreBeanInfo(environment); //启动后console的打印出来的一堆配置信息 Banner printedBanner = this.printBanner(environment); //ApplicationContext实例化 context = this.createApplicationContext(); exceptionReporters = this.getSpringFactoriesInstances(SpringBootExceptionReporter.class, new Class[]{ConfigurableApplicationContext.class}, context); this.prepareContext(context, environment, listeners, applicationArguments, printedBanner); this.refreshContext(context); this.afterRefresh(context, applicationArguments); stopWatch.stop(); if (this.logStartupInfo) { (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch); } listeners.started(context); this.callRunners(context, applicationArguments); } catch (Throwable var10) { this.handleRunFailure(context, var10, exceptionReporters, listeners); throw new IllegalStateException(var10); } try { listeners.running(context); return context; } catch (Throwable var9) { this.handleRunFailure(context, var9, exceptionReporters, (SpringApplicationRunListeners)null); throw new IllegalStateException(var9); } }

创建applicationContext又分为几步:createApplicationContext、prepareContext、refreshContext。实例化applicationContext会根据在之前我们说的webEnvironment这个属性判断是使用webContext类AnnotationConfigEmbeddedWebApplicationContext还是普通context类AnnotationConfigApplicationContext(在这里我们使用的是webContext为例)然后通过反射进行实例化。applicationContext实例化完了会进入prepareContext流程,这个prepareContext方法会加载之前准备好的environment进入context中,然后如果有beanNameGenerator和resourceLoader那么提前创建bean加载进applicationContext,但是一般这两个都是空的,所以直接进入applyInitializers方法,将之前实例化的所有initializers进行初始化,所有的bean就是在这里进行bean的扫描和加载的因这次讲的是启动过程,所以不再细讲。最后是refreshContext,这个就和spring的bean加载过程一致了,bean的注入、beanFactory、postProcessBeanFactory等等,详情可以去看看spring bean的生命周期 。最后把创建好的applicationContext设置进入listener,prepareContext过程就结束了。(此段为引用)

总结:

1、创建SpringApplication实例,判定环境,是web环境还是普通环境。加载所有需要用到的Initializers和Listeners,这里使用约定大于配置的理念揭开了自动配置的面纱。 2、创建一个ApplicationContext,设置装配context。最终将装配好的context作为属性设置进SpringApplicationRunListeners。

参考博客:

spring boot启动流程图:https://www.pianshen.com/article/6036196723/

https://www.jb51.net/article/124286.htm

最新回复(0)