title: SpringBoot启动流程—-SpringApplication类
author: thetianxia
readmore: true
categories: [Java,框架]
tags: [Java,面试,SpringBoot]


SpringBoot启动类 2.4.5

  1. @SpringBootApplication
  2. public class Application {
  3. public static void main(String[] args) {
  4. SpringApplication.run(Application.class);
  5. }
  6. }

启动类的代码非常简单,我们只需要在SpringBoot项目启动类加上注解@SpringBootApplication,即可标注该类是启动类。在该类的main方法中调用了

SpringApplication.run(Application.class),所以启动流程就在run中。通过debug,我们看一下源码。

  1. //1、main方法进来之后,调用了这个run方法,然后这个run又封装了一下参数,调用另一个重载方法run
  2. public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  3. return run(new Class[]{primarySource}, args);
  4. }
  5. //2、该run方法,首先新创建一个SpringApplication,该类构造器接受一个启动类参数对象,在构造器中,SpringBoot进行了一系列参数初始化。
  6. public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
  7. return (new SpringApplication(primarySources)).run(args);
  8. }

SpringApplication构造器,初始化

  1. //3、run方法创建新的SpringApplication对象,调用该构造器,该构造器又调用另一个构造器
  2. public SpringApplication(Class<?>... primarySources) {
  3. //默认资源加载器ResourceLoader为null
  4. this((ResourceLoader)null, primarySources);
  5. }
  6. //4、初始化
  7. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  8. this.sources = new LinkedHashSet(); //配置sources
  9. this.bannerMode = Mode.CONSOLE; //配置横幅,默认打印到控制台。Mode枚举 OFF关闭,CONSOLE控制台打印,LOG日志打印;
  10. this.logStartupInfo = true; //配置是否开启日志,默认开启
  11. this.addCommandLineProperties = true; //配置是否添加命令行属性,默认开启
  12. this.addConversionService = true; //是否添加转换服务,默认开启
  13. this.headless = true; //headless模式
  14. this.registerShutdownHook = true;
  15. this.additionalProfiles = Collections.emptySet();
  16. this.isCustomEnvironment = false;
  17. this.lazyInitialization = false;
  18. this.applicationContextFactory = ApplicationContextFactory.DEFAULT;
  19. this.applicationStartup = ApplicationStartup.DEFAULT; //DefaultApplicationStartup
  20. this.resourceLoader = resourceLoader; //null
  21. Assert.notNull(primarySources, "PrimarySources must not be null"); //如果没有启动类,启动失败。primarySources一般只有一个启动类,或者null
  22. this.primarySources = new LinkedHashSet(Arrays.asList(primarySources)); //保存主配置类
  23. this.webApplicationType = WebApplicationType.deduceFromClasspath(); //判断web类型,SERVLET
  24. this.bootstrapRegistryInitializers = this.getBootstrapRegistryInitializersFromSpringFactories(); //获取所有的BootstrapRegistryInitializer实现类保存在List<BootstrapRegistryInitializer> bootstrapRegistryInitializers,锚点1
  25. this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class)); //从资源文件配置ApplicationContextInitializer实例并存在List<ApplicationContextInitializer<?>> initializers;锚点2
  26. this.setListeners(this.getSpringFactoriesInstances(ApplicationListener.class)); //从资源文件创建应用监听器,保存在List<ApplicationListener<?>> listeners
  27. this.mainApplicationClass = this.deduceMainApplicationClass(); //配置应用的主方法所在类
  28. }

锚点1

SpringBoot启动时初始化上下文时,最终会调用该方法。再改方法中获取classLoader,因为构造器中resourceLoader是null,所以得到的是默认构造器

然后执行该方法SpringFactoriesLoader.loadFactoryNames(type, classLoader),锚点1之后的流程如下。

  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
  2. return this.getSpringFactoriesInstances(type, new Class[0]);
  3. }
  4. //最终会调用该方法。
  5. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  6. ClassLoader classLoader = this.getClassLoader(); //return this.resourceLoader != null ? this.resourceLoader.getClassLoader() : ClassUtils.getDefaultClassLoader();返回系统默认类加载器
  7. Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  8. List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  9. AnnotationAwareOrderComparator.sort(instances);
  10. return instances;
  11. }

然后进入SpringFactoriesLoader.loadFactoryNames(type, classLoader)。

  1. public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
  2. ClassLoader classLoaderToUse = classLoader; //默认加载器
  3. if (classLoader == null) {
  4. classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
  5. }
  6. String factoryTypeName = factoryType.getName(); //锚点1处是BootstrapRegistryInitializer.class类的全类名
  7. return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
  8. }

获得全类名之后,进入loadSpringFactories(classLoaderToUse)方法,并得到一个Map类。该方法会从”META-INF/spring.factories”下的文件中读取配置。SpringBoot中只有如图三个路径下存在”META-INF/spring.factories”。我们以锚点1的BootstrapRegistryInitializer为例。

1.png

urls中存在3个地址,分别在spring-boot,spring-boot-autoconfigure,spring-beans中。循环将对应地址的文件读入为properties,内容如下图。

2.png

如果缓存没有,则读取配置文件,获得Enumeration类型的urls,Enumeration的key是HashTable并且对应的值也存于HashTable中。因此该类将配置文件中的内容做映射。之后通过迭代,获得每一个key和对应的values。

  1. private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
  2. //先从缓存获取,如果有就直接返回
  3. Map<String, List<String>> result = (Map)cache.get(classLoader);
  4. if (result != null) {
  5. return result;
  6. } else {
  7. HashMap result = new HashMap();
  8. try {
  9. //没有则从"META-INF/spring.factories"文件中读取,获取"META-INF/spring.factories"的url
  10. Enumeration urls = classLoader.getResources("META-INF/spring.factories");
  11. //遍历url
  12. while(urls.hasMoreElements()) {
  13. URL url = (URL)urls.nextElement();
  14. UrlResource resource = new UrlResource(url);
  15. Properties properties = PropertiesLoaderUtils.loadProperties(resource); //从url中读入数据
  16. Iterator var6 = properties.entrySet().iterator(); //获得迭代器
  17. //迭代
  18. while(var6.hasNext()) {
  19. Entry<?, ?> entry = (Entry)var6.next(); //String,String
  20. String factoryTypeName = ((String)entry.getKey()).trim(); //去掉key字符串开头和结尾的空白
  21. //value转为数组
  22. String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String)entry.getValue()); //将value字符转为数组
  23. String[] var10 = factoryImplementationNames;
  24. int var11 = factoryImplementationNames.length;
  25. for(int var12 = 0; var12 < var11; ++var12) {
  26. String factoryImplementationName = var10[var12];
  27. ((List)result.computeIfAbsent(factoryTypeName, (key) -> { //第一次会返回空数组,并将第一个元素去掉开头和结尾的空白并添加到数组,之后都获取该数组并向其中添加元素。
  28. return new ArrayList();
  29. })).add(factoryImplementationName.trim());
  30. }
  31. }
  32. }
  33. //最后将map中所有key对应的value去重后更新
  34. result.replaceAll((factoryType, implementations) -> {
  35. return (List)implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList));
  36. });
  37. cache.put(classLoader, result); //放入缓存
  38. return result; //返回map
  39. } catch (IOException var14) {
  40. throw new IllegalArgumentException("Unable to load factories from location [META-INF/spring.factories]", var14);
  41. }
  42. }
  43. }

返回之后,会通过getOrDefault方法返回BootstrapRegistryInitializer.class对应的配置集合。然后执行List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);

该方法通过反射,用names中的全部类的全类名创建实例对象集合,然后排序之后返回。

3.png

返回之后,保存到SpringApplication对象的属性中。

锚点2

初始化BootstrapRegistryInitializer.class之后,会初始化ApplicationContextInitializer和ApplicationListener监听器相关的类。过程同锚点1一样。只不过在loadSpringFactories方法中,会直接返回缓存中的map并返回对应的list。

Run具体启动

  1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch(); //计时
  3. stopWatch.start();
  4. DefaultBootstrapContext bootstrapContext = this.createBootstrapContext();
  5. ConfigurableApplicationContext context = null;
  6. this.configureHeadlessProperty();
  7. //创建并启动监听器
  8. SpringApplicationRunListeners listeners = this.getRunListeners(args); //锚点3,获取监听器
  9. listeners.starting(bootstrapContext, this.mainApplicationClass); //锚点4,启动监听器
  10. try {
  11. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  12. ConfigurableEnvironment environment = this.prepareEnvironment(listeners, bootstrapContext, applicationArguments); //锚点7,准备环境
  13. this.configureIgnoreBeanInfo(environment);
  14. Banner printedBanner = this.printBanner(environment); //根据配置打印banner
  15. //创建ioc
  16. context = this.createApplicationContext();
  17. context.setApplicationStartup(this.applicationStartup);
  18. this.prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  19. this.refreshContext(context);
  20. this.afterRefresh(context, applicationArguments);
  21. stopWatch.stop();
  22. if (this.logStartupInfo) {
  23. (new StartupInfoLogger(this.mainApplicationClass)).logStarted(this.getApplicationLog(), stopWatch);
  24. }
  25. listeners.started(context);
  26. this.callRunners(context, applicationArguments);
  27. } catch (Throwable var10) {
  28. this.handleRunFailure(context, var10, listeners);
  29. throw new IllegalStateException(var10);
  30. }
  31. try {
  32. listeners.running(context);
  33. return context;
  34. } catch (Throwable var9) {
  35. this.handleRunFailure(context, var9, (SpringApplicationRunListeners)null);
  36. throw new IllegalStateException(var9);
  37. }
  38. }

锚点3

SpringApplicationRunListeners listeners = this.getRunListeners(args);这个方法比较重要,目的是获取一个封装的SpringApplicationRunListeners对象。该类中一个属性List listeners中最后会有一个元素EventPublishingRunListener。

4.png

下面,通过断点,我们看一下封装过程。

可以看到getRunListeners直接new了一个SpringApplicationRunListeners。之后我们看该构造函数,现在我们先看参数this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args)最后会是什么。

  1. private SpringApplicationRunListeners getRunListeners(String[] args) {
  2. Class<?>[] types = new Class[]{SpringApplication.class, String[].class};
  3. return new SpringApplicationRunListeners(logger, this.getSpringFactoriesInstances(SpringApplicationRunListener.class, types, this, args), this.applicationStartup);
  4. }

这个方法,我们在之前SpringApplication构造其中,就见过多次。它从一个map中获取对应的List集合。我们进去看一下,果然,一样的配方。最后names只有一个元素,就是EventPublishingRunListener类的全限定类名。之后又调用了List instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);这行代码进行反射获取实例。最后代码会运行到EventPublishingRunListener的构造器处。我们往下看。

5.png

标注的这一行,将过去的构造函数和参数传入,反射创建对象。

6.png

ctor就是上一步的传入的构造函数,这里直接传入参数开始构建。参数中包含的就是之前new的并且初始化的SpringApplication对象。
7.png

调用EventPublishingRunListener构造器创建对象。该类有三个参数,application是通过参数传递的,用来获取初始化时创建的监听器对象集合,并获取迭代器var3。然后将监听器封装到initialMulticaster属性中。initialMulticaster的类型是 public class SimpleApplicationEventMulticaster extends AbstractApplicationEventMulticaster,它的父类中,有一个内部类,该内部类中有一个集合,最终这些listener会存到该集合中。

8.png

内部类部分代码

  1. public void addApplicationListener(ApplicationListener<?> listener) {
  2. synchronized(this.defaultRetriever) {
  3. Object singletonTarget = AopProxyUtils.getSingletonTarget(listener);
  4. if (singletonTarget instanceof ApplicationListener) {
  5. this.defaultRetriever.applicationListeners.remove(singletonTarget);
  6. }
  7. this.defaultRetriever.applicationListeners.add(listener);
  8. this.retrieverCache.clear();
  9. }
  10. }
  11. //内部类
  12. private class DefaultListenerRetriever {
  13. public final Set<ApplicationListener<?>> applicationListeners; //最终存放监听器处
  14. public final Set<String> applicationListenerBeans;
  15. private DefaultListenerRetriever() {
  16. this.applicationListeners = new LinkedHashSet();
  17. this.applicationListenerBeans = new LinkedHashSet();
  18. }
  19. }

因为初始化一共有9个监听器,所以最终这个集合里面会添加9个监听器。如下图,返回的参数就是instances,里面封装了一个EventPublishingRunListener,EventPublishingRunListener里面有个属性initialMulticaster,里面又封装了一个包含9个监听器的集合。封装套娃。。。。最后通过SpringApplicationRunListeners构造函数,赋值给listeners。最后返回生成的SpringApplicationRunListeners对象。

9.png

到此为止,锚点3结束。如果套的头晕,建议多看几遍就好了。

锚点4

获得监听器之后,启动监听器。这个方法最后调用了doWithListeners方法。我们可以看到里面将linsteners中的监听器(其实就是EventPublishingRunListener)分别执行lambda中listener.starting(bootstrapContext),所以我们去EventPublishingRunListener中找对应的方法。

  1. void starting(ConfigurableBootstrapContext bootstrapContext, Class<?> mainApplicationClass) {
  2. this.doWithListeners("spring.boot.application.starting", (listener) -> {
  3. listener.starting(bootstrapContext);
  4. }, (step) -> {
  5. if (mainApplicationClass != null) {
  6. step.tag("mainApplicationClass", mainApplicationClass.getName());
  7. }
  8. });
  9. }
  10. private void doWithListeners(String stepName, Consumer<SpringApplicationRunListener> listenerAction, Consumer<StartupStep> stepAction) {
  11. StartupStep step = this.applicationStartup.start(stepName);
  12. this.listeners.forEach(listenerAction);
  13. if (stepAction != null) {
  14. stepAction.accept(step);
  15. }
  16. step.end();
  17. }

调用该方法

10.png

然后来到SimpleApplicationEventMulticaster,最终调用的是下面这个方法。该方法中,重要的是Iterator var5 = this.getApplicationListeners(event, type).iterator();获取符合eventType的监听器的迭代器。我们进入看下。

  1. public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType eventType) {
  2. ResolvableType type = eventType != null ? eventType : this.resolveDefaultEventType(event);
  3. Executor executor = this.getTaskExecutor(); //null
  4. Iterator var5 = this.getApplicationListeners(event, type).iterator(); //锚点5
  5. //从锚点6回来,遍历符合条件的监听器,并执行
  6. while(var5.hasNext()) {
  7. ApplicationListener<?> listener = (ApplicationListener)var5.next();
  8. if (executor != null) {
  9. executor.execute(() -> {
  10. this.invokeListener(listener, event);
  11. });
  12. } else {
  13. //执行
  14. this.invokeListener(listener, event);
  15. }
  16. }
  17. }

this.invokeListener(listener, event)最后会执行到这里,根据监听器执行不同的逻辑。

锚点5

  1. protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
  2. Object source = event.getSource(); //初始化创建的SpringApplication对象
  3. Class<?> sourceType = source != null ? source.getClass() : null; //SpringApplication的全限定类名
  4. AbstractApplicationEventMulticaster.ListenerCacheKey cacheKey = new AbstractApplicationEventMulticaster.ListenerCacheKey(eventType, sourceType); //将eventType和sourceType封装一个key,后面获取 existingRetriever
  5. AbstractApplicationEventMulticaster.CachedListenerRetriever newRetriever = null;
  6. AbstractApplicationEventMulticaster.CachedListenerRetriever existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.get(cacheKey); //因为开始缓存没有,所以是null,所以进入下边的if
  7. if (existingRetriever == null && (this.beanClassLoader == null || ClassUtils.isCacheSafe(event.getClass(), this.beanClassLoader) && (sourceType == null || ClassUtils.isCacheSafe(sourceType, this.beanClassLoader)))) {
  8. //因为第一次retrieverCache缓存没有,所以new了一个newRetriever,然后放入缓存,cacheKey作为key,newRetriever作为值
  9. newRetriever = new AbstractApplicationEventMulticaster.CachedListenerRetriever();
  10. //因为不存在,所以newRetriever被放入,返回null,所以existingRetriever是null
  11. existingRetriever = (AbstractApplicationEventMulticaster.CachedListenerRetriever)this.retrieverCache.putIfAbsent(cacheKey, newRetriever);
  12. if (existingRetriever != null) {
  13. newRetriever = null;
  14. }
  15. }
  16. //existingRetriever==null,不会执行
  17. if (existingRetriever != null) {
  18. Collection<ApplicationListener<?>> result = existingRetriever.getApplicationListeners(); //符合条件的监听器集合,分析见锚点6
  19. if (result != null) {
  20. return result;
  21. }
  22. }
  23. //这一步筛选符合条件的监听器并返回。锚点6
  24. return this.retrieveApplicationListeners(eventType, sourceType, newRetriever);
  25. }

锚点6

11.png

  1. private Collection<ApplicationListener<?>> retrieveApplicationListeners(ResolvableType eventType, @Nullable Class<?> sourceType, @Nullable AbstractApplicationEventMulticaster.CachedListenerRetriever retriever) {
  2. List<ApplicationListener<?>> allListeners = new ArrayList();
  3. Set<ApplicationListener<?>> filteredListeners = retriever != null ? new LinkedHashSet() : null;
  4. Set<String> filteredListenerBeans = retriever != null ? new LinkedHashSet() : null;
  5. LinkedHashSet listeners;
  6. LinkedHashSet listenerBeans;
  7. synchronized(this.defaultRetriever) {
  8. //我们 锚点3分析过,this.defaultRetriever.applicationListeners存放的是加载classpath路径下的9个监听器
  9. //这里加锁,为了防止在执行这一步的同时值被其他线程修改
  10. listeners = new LinkedHashSet(this.defaultRetriever.applicationListeners);
  11. listenerBeans = new LinkedHashSet(this.defaultRetriever.applicationListenerBeans);
  12. }
  13. Iterator var9 = listeners.iterator();
  14. while(var9.hasNext()) {
  15. ApplicationListener<?> listener = (ApplicationListener)var9.next();
  16. //通过方法名字,我们可以推测,如果listener符合eventType和sourceType,那么返回true,最终有4个监听器满足
  17. if (this.supportsEvent(listener, eventType, sourceType)) {
  18. if (retriever != null) {
  19. //第一次加入filteredListeners
  20. filteredListeners.add(listener);
  21. }
  22. //符合条件加入filteredListeners
  23. allListeners.add(listener);
  24. }
  25. }
  26. //listenerBeans大小为0,不会执行
  27. if (!listenerBeans.isEmpty()) {
  28. ConfigurableBeanFactory beanFactory = this.getBeanFactory();
  29. Iterator var16 = listenerBeans.iterator();
  30. while(var16.hasNext()) {
  31. String listenerBeanName = (String)var16.next();
  32. try {
  33. if (this.supportsEvent(beanFactory, listenerBeanName, eventType)) {
  34. ApplicationListener<?> listener = (ApplicationListener)beanFactory.getBean(listenerBeanName, ApplicationListener.class);
  35. if (!allListeners.contains(listener) && this.supportsEvent(listener, eventType, sourceType)) {
  36. if (retriever != null) {
  37. if (beanFactory.isSingleton(listenerBeanName)) {
  38. filteredListeners.add(listener);
  39. } else {
  40. filteredListenerBeans.add(listenerBeanName);
  41. }
  42. }
  43. allListeners.add(listener);
  44. }
  45. } else {
  46. Object listener = beanFactory.getSingleton(listenerBeanName);
  47. if (retriever != null) {
  48. filteredListeners.remove(listener);
  49. }
  50. allListeners.remove(listener);
  51. }
  52. } catch (NoSuchBeanDefinitionException var13) {
  53. }
  54. }
  55. }
  56. AnnotationAwareOrderComparator.sort(allListeners);
  57. //将过滤的结果存入缓存,下次通过cacheKey直接获取
  58. if (retriever != null) {
  59. if (filteredListenerBeans.isEmpty()) {
  60. retriever.applicationListeners = new LinkedHashSet(allListeners);
  61. retriever.applicationListenerBeans = filteredListenerBeans;
  62. } else {
  63. retriever.applicationListeners = filteredListeners;
  64. retriever.applicationListenerBeans = filteredListenerBeans;
  65. }
  66. }
  67. return allListeners; //锚点6结束,回到锚点4
  68. }

锚点7

  1. private ConfigurableEnvironment prepareEnvironment(SpringApplicationRunListeners listeners, DefaultBootstrapContext bootstrapContext, ApplicationArguments applicationArguments) {
  2. ConfigurableEnvironment environment = this.getOrCreateEnvironment(); //获取系统配置信息,以及控制台配置
  3. this.configureEnvironment((ConfigurableEnvironment)environment, applicationArguments.getSourceArgs());
  4. ConfigurationPropertySources.attach((Environment)environment);
  5. listeners.environmentPrepared(bootstrapContext, (ConfigurableEnvironment)environment); //处理环境准备完成相关的监听器,过程参考锚点3到锚点6,不同的是type,因此广播的监听器不同。
  6. DefaultPropertiesPropertySource.moveToEnd((ConfigurableEnvironment)environment);
  7. this.configureAdditionalProfiles((ConfigurableEnvironment)environment);
  8. this.bindToSpringApplication((ConfigurableEnvironment)environment);
  9. if (!this.isCustomEnvironment) {
  10. environment = (new EnvironmentConverter(this.getClassLoader())).convertEnvironmentIfNecessary((ConfigurableEnvironment)environment, this.deduceEnvironmentClass());
  11. }
  12. ConfigurationPropertySources.attach((Environment)environment);
  13. return (ConfigurableEnvironment)environment;
  14. }

我们进入getOrCreateEnvironment方法,因为开始的时候环境是空,所以这里会创建StandardServletEnvironment(),里面进去这里会先调用父类的构造器,StandardEnvironment,AbstractEnvironment。

12.png

所以最终调用的是AbstractEnvironment的构造器,具体逻辑也是在这里执行的。

13.png

14.png

这段逻辑里面,进行了一些初始值的设置,然后再最后一行代码进行了重要的操作。最后一行代码执行的不是该类的方法,而是StandardServletEnvironment类的重写方法。

22.png

StandardServletEnvironment执行该方法后,又调用父类StandardEnvironment的重写方法。

这里进行了一些初值的设置。

15.png

重点在父类中。getSystemProperties方法中,会调用System.getProperties(),从这个方法里面就可以获取计算机系统的属性。
16.png

接下来会执行这一句。具体作用就如同注释一样。因为到这里环境准备的差不多了,所以就要处理环境准备之后的一些监听器。因此eventType类型是ApplicationEnvironmentPreparedEvent,找到之后进行广播。

17.png

锚点8

web项目,会创建一个AnnotationConfigServletWebServerApplicationContext()类。
18.png

之后创建启动器,在准备需要创建的beans。

19.png

prepareContext中会调用下面这个方法。可以看到,这里将this.setInitializers(this.getSpringFactoriesInstances(ApplicationContextInitializer.class))这个地方从配置中读到的初始化相关类进行遍历,并且初始化。初始化前会进行断言,如果不能初始化则抛出异常。

之后会执行相应的监听器。并且会注册单例对象的类名。

20.png

prepareContext执行完毕之后,会调用refreshContext方法,该方法会将容器的对象刷新激活,之后处理刷新之后的操作。

在激活对象的时候,我们深入会发现,在refresh方法中,会调用onRefresh方法。在这个地方会启动tomcat。启动tomcat之后还会加载一些其他bean。

21.png

到此,springboot启动完毕。