版本信息

Spring Boot 2.5.4

启动的两步

  1. 启动类上注解@SpringBootApplication
  2. 启动类中的main方法:org.springframework.boot.SpringApplication#run(java.lang.Class<?>, java.lang.String…)

本篇只记录第二步,第一步见SpringBoot | SpringBoot中的注解-SpringBoot启动篇

SpringBoot的启动流程图解

SpringBoot | SpringBoot的启动流程 - 图1

源码执行流程解析

  1. @SpringBootApplication
  2. @MapperScan(basePackages = {"com.ybqdren.mapper"} )
  3. @ComponentScan(basePackages = {"com.ybqdren","org.n3r.idworker"})
  4. public class Application {
  5. public static void main(String[] args){
  6. SpringApplication.run(Application.class,args);
  7. }
  8. }

进入 EventPublishingRunListener#EventPublishingRunListener:
image.png
不过这里目前没有监听器。

进入 SpringApplication#run:

  1. public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
  2. return run(new Class<?>[] { primarySource }, args);
  3. }

调用另一个同名的重载方法 SpringApplication#run。

进入 SpringApplication#run,创建一个SpringApplication的实例对象:

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

进入其构造方法 SpringApplicaion#SpringApplication。

进入 SpringApplicaion#SpringApplication:

  1. @SuppressWarnings({ "unchecked", "rawtypes" })
  2. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  3. this.resourceLoader = resourceLoader;
  4. Assert.notNull(primarySources, "PrimarySources must not be null");
  5. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  6. // 初始化了webApplicationType ,比如此处是“SERVLET”
  7. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  8. setInitializers((Collection) getSpringFactoriesInstances(
  9. ApplicationContextInitializer.class));
  10. // 初始化了几个listener监听器,比如此处是 8 个
  11. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  12. this.mainApplicationClass = deduceMainApplicationClass();
  13. }

上面这个过程,主要是初始化成员变量.

比如应用类型(比如此处 webApplicationType 值为SERVLET):
image.png

比如初始化监听器:
image.png

比如通过 SpringApplicaion#getBootstrapRegistryInitializersFromSpringFactories 初始化了:
SpringBoot | SpringBoot的启动流程 - 图5

比如通过 SpringApplicaion#getSpringFactoriesInstances(ApplicationContextInitializer.class) 初始化了:
SpringBoot | SpringBoot的启动流程 - 图6

进入 SpringApplication#run:

  1. public ConfigurableApplicationContext run(String... args) {
  2. StopWatch stopWatch = new StopWatch();
  3. stopWatch.start();
  4. DefaultBootstrapContext bootstrapContext = createBootstrapContext();
  5. ConfigurableApplicationContext context = null;
  6. configureHeadlessProperty();
  7. SpringApplicationRunListeners listeners = getRunListeners(args);
  8. listeners.starting(bootstrapContext, this.mainApplicationClass);
  9. try {
  10. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  11. ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
  12. configureIgnoreBeanInfo(environment);
  13. Banner printedBanner = printBanner(environment);
  14. context = createApplicationContext();
  15. context.setApplicationStartup(this.applicationStartup);
  16. prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
  17. refreshContext(context);
  18. afterRefresh(context, applicationArguments);
  19. stopWatch.stop();
  20. // 如果 logStartupInfo 为 true 就输出类似下面这样的日志:
  21. // INFO Application:61 - Started Application in 93.379 seconds (JVM running for 112.224)
  22. if (this.logStartupInfo) {
  23. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  24. }
  25. listeners.started(context);
  26. callRunners(context, applicationArguments);
  27. }
  28. catch (Throwable ex) {
  29. handleRunFailure(context, ex, listeners);
  30. throw new IllegalStateException(ex);
  31. }
  32. try {
  33. listeners.running(context);
  34. }
  35. catch (Throwable ex) {
  36. handleRunFailure(context, ex, null);
  37. throw new IllegalStateException(ex);
  38. }
  39. return context;
  40. }

此处是使用了观察者模式。

  1. 创建一个 StopWatch 实例,用来记录 Spring Boot 的启动时间

image.png

  1. 通过 SpringFactoriesLoader 加载 listeners

通过 SpringFactoriesLoader#loadFactoryNames 方法从核心配置文件中获取到了org.springframework.boot.SpringApplicationRunListener :
image.png
而其只有一个实现类 EventPublishingRunListener:
image.png
所以此处会加载 EventPublishingRunListener 这个监听器。

  1. 发布 Sprint Boot 开始启动事件

进入 EventPublishingRunListener#starting 开启事件:

  1. @Override
  2. public void starting(ConfigurableBootstrapContext bootstrapContext) {
  3. this.initialMulticaster
  4. .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
  5. }
  1. 创建和配置environment

进入 EventPublishingRunListener#environmentPrepared 配置各种配置参数:

  1. @Override
  2. public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
  3. ConfigurableEnvironment environment) {
  4. this.initialMulticaster.multicastEvent(
  5. new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
  6. }

比如:
interface org.springframework.boot.env.EnvironmentPostProcessor
interface org.springframework.boot.context.config.ConfigDataLocationResolver
interface org.springframework.boot.env.PropertySourceLoader
interface org.springframework.boot.context.config.ConfigDataLoader

  1. 打印SpringBoot的banner和版本(可能还会打印一些环境的版本信息)

image.png
image.png

  1. 创建对应的ApplicationContext:Web类型

进入 ApplicationContextFactory:
image.png

返回 SERVLET 。

Reactive类型,普通的类型(非Web)

  1. prepareContext

进入 SpringApplication#prepareContext:

  1. private void prepareContext(DefaultBootstrapContext bootstrapContext, ConfigurableApplicationContext context,
  2. ConfigurableEnvironment environment, SpringApplicationRunListeners listeners,
  3. ApplicationArguments applicationArguments, Banner printedBanner) {
  4. context.setEnvironment(environment);
  5. postProcessApplicationContext(context);
  6. applyInitializers(context);
  7. listeners.contextPrepared(context);
  8. bootstrapContext.close(context);
  9. if (this.logStartupInfo) {
  10. logStartupInfo(context.getParent() == null);
  11. logStartupProfileInfo(context);
  12. }
  13. // Add boot specific singleton beans
  14. ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
  15. beanFactory.registerSingleton("springApplicationArguments", applicationArguments);
  16. if (printedBanner != null) {
  17. beanFactory.registerSingleton("springBootBanner", printedBanner);
  18. }
  19. if (beanFactory instanceof DefaultListableBeanFactory) {
  20. ((DefaultListableBeanFactory) beanFactory)
  21. .setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
  22. }
  23. if (this.lazyInitialization) {
  24. context.addBeanFactoryPostProcessor(new LazyInitializationBeanFactoryPostProcessor());
  25. }
  26. // Load the sources
  27. Set<Object> sources = getAllSources();
  28. Assert.notEmpty(sources, "Sources must not be empty");
  29. load(context, sources.toArray(new Object[0]));
  30. listeners.contextLoaded(context);
  31. }

1) 准备ApplicationContext,通过 EventPublishingRunListener#contextPrepared 初始化;
image.png

2) 打印启动日志,打印profile信息(如dev, test, prod)
调用 SpringApplication#logStartupInfo方法,在控制台打印:
image.png
调用 SpringApplication#logStartupProfileInfo方法,在控制台打印:
image.png

3) 最终会调用到AbstractApplicationContext#refresh方法,实际上就是Spring IOC容器的创建过程,并且会进行自动装配的操作,以及发布ApplicationContext已经refresh事件,标志着ApplicationContext初始化完成(contextLoaded())
此处的日志输出:

  1. INFO TomcatWebServer:108 - Tomcat initialized with port(s): 8088 (http)
  2. 12 11, 2021 6:19:01 下午 org.apache.catalina.core.StandardService startInternal
  3. 信息: Starting service [Tomcat]
  4. 12 11, 2021 6:19:01 下午 org.apache.catalina.core.StandardEngine startInternal
  5. 信息: Starting Servlet engine: [Apache Tomcat/9.0.52]
  6. 12 11, 2021 6:19:01 下午 org.apache.catalina.core.ApplicationContext log
  7. 信息: Initializing Spring embedded WebApplicationContext
  8. INFO ServletWebServerApplicationContext:290 - Root WebApplicationContext: initialization completed in 1603 ms
  9. Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
  10. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\CarouselMapper.xml]'
  11. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\CategoryMapper.xml]'
  12. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\CategoryMapperCustom.xml]'
  13. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\ItemsCommentsMapper.xml]'
  14. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\ItemsImgMapper.xml]'
  15. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\ItemsMapper.xml]'
  16. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\ItemsMapperCustom.xml]'
  17. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\ItemsParamMapper.xml]'
  18. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\ItemsSpecMapper.xml]'
  19. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\OrderItemsMapper.xml]'
  20. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\OrderStatusMapper.xml]'
  21. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\OrdersMapper.xml]'
  22. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\StuMapper.xml]'
  23. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\UserAddressMapper.xml]'
  24. Parsed mapper file: 'file [D:\Zhao\Code\CourseCode\Java技术专家\code\architectural-evolution-of-Java-applications-learn\foodie-dev\foodie-dev-mapper\target\classes\mapper\UsersMapper.xml]'
  25. INFO MapperCacheDisabler:60 - Clear tk.mybatis.mapper.util.MsUtil CLASS_CACHE cache.
  26. INFO MapperCacheDisabler:60 - Clear tk.mybatis.mapper.genid.GenIdUtil CACHE cache.
  27. INFO MapperCacheDisabler:60 - Clear tk.mybatis.mapper.version.VersionUtil CACHE cache.
  28. INFO MapperCacheDisabler:83 - Clear EntityHelper entityTableMap cache.
  29. Logging initialized using 'class org.apache.ibatis.logging.stdout.StdOutImpl' adapter.
  30. INFO TomcatWebServer:220 - Tomcat started on port(s): 8088 (http) with context path ''
  31. INFO DocumentationPluginsBootstrapper:84 - Context refreshed
  32. INFO DocumentationPluginsBootstrapper:87 - Found 1 custom documentation plugin(s)
  33. INFO ApiListingReferenceScanner:44 - Scanning for api listing references
  34. INFO CachingOperationNameGenerator:40 - Generating unique operation named: updateUsingPOST_1
  35. INFO CachingOperationNameGenerator:40 - Generating unique operation named: userinfoUsingGET_1
  36. INFO CachingOperationNameGenerator:40 - Generating unique operation named: setSessionUsingGET_1
  37. INFO CachingOperationNameGenerator:40 - Generating unique operation named: searchUsingGET_1
  38. INFO CachingOperationNameGenerator:40 - Generating unique operation named: sixNewItemsUsingGET_1
  39. INFO CachingOperationNameGenerator:40 - Generating unique operation named: addUsingPOST_1
  1. afterRefresh hook方法

作用是刷新上下文后调用,在当前版本中,此方法没有实现??
image.png

  1. stopWatch停止计时,日志打印总共启动的时间

image.png

  1. 发布SpringBoot程序已启动事件

进入 EventPublishingRunListener#started 方法:

  1. @Override
  2. public void started(ConfigurableApplicationContext context) {
  3. context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
  4. AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
  5. }

image.png

  1. 调用ApplicationRunner和CommandLineRunner

SpringApplication#callRunners

  1. private void callRunners(ApplicationContext context, ApplicationArguments args) {
  2. List<Object> runners = new ArrayList<>();
  3. runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
  4. runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
  5. AnnotationAwareOrderComparator.sort(runners);
  6. for (Object runner : new LinkedHashSet<>(runners)) {
  7. if (runner instanceof ApplicationRunner) {
  8. callRunner((ApplicationRunner) runner, args);
  9. }
  10. if (runner instanceof CommandLineRunner) {
  11. callRunner((CommandLineRunner) runner, args);
  12. }
  13. }
  14. }
  1. 最后发布就绪事件ApplicationReadyEvent,标志着SpringBoot可以处理就收的请求了

进入 EventPublishingRunListener#running 方法:

  1. @Override
  2. public void running(ConfigurableApplicationContext context) {
  3. context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
  4. AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
  5. }

相关方法与作用解析

SpringApplicaion::SpringApplication

SpringApplicaion#getSpringFactoriesInstances

  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  2. ClassLoader classLoader = getClassLoader();
  3. // Use names and ensure unique to protect against duplicates
  4. Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  5. List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  6. AnnotationAwareOrderComparator.sort(instances);
  7. return instances;
  8. }
  • SpringFactoriesLoader#loadFactoryNames

    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();
    7. return (List)loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
    8. }

    到 SpringFactoriesLoader#loadSpringFactories中获取,此方法使用classloader的双亲委派机制:
    image.png

从spring.factories中获取type对应的配置类名称列表:
image.png
此文件位于对应包的META-INF文件夹下:
image.png
image.png

  • SpringFactoriesLoader#createSpringFactoriesInstances
    1. @SuppressWarnings("unchecked")
    2. private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
    3. ClassLoader classLoader, Object[] args, Set<String> names) {
    4. List<T> instances = new ArrayList<>(names.size());
    5. for (String name : names) {
    6. try {
    7. Class<?> instanceClass = ClassUtils.forName(name, classLoader);
    8. Assert.isAssignable(type, instanceClass);
    9. Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
    10. T instance = (T) BeanUtils.instantiateClass(constructor, args);
    11. instances.add(instance);
    12. }
    13. catch (Throwable ex) {
    14. throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
    15. }
    16. }
    17. return instances;
    18. }
    校验获取到的类是否是parameterTypes类的子类,并将获取到的类通过反射机制实例化。

AbstractApplicationContext#refresh

  1. /**
  2. * Refresh the underlying {@link ApplicationContext}.
  3. * @param applicationContext the application context to refresh
  4. */
  5. protected void refresh(ConfigurableApplicationContext applicationContext) {
  6. applicationContext.refresh();
  7. }

进入 ServletWebServerApplicationContext#refresh :

  1. @Override
  2. public final void refresh() throws BeansException, IllegalStateException {
  3. try {
  4. super.refresh();
  5. }
  6. catch (RuntimeException ex) {
  7. WebServer webServer = this.webServer;
  8. if (webServer != null) {
  9. webServer.stop();
  10. }
  11. throw ex;
  12. }
  13. }

创建的过程(AnnotationConfigApplicationContext的构造方法),由于debug过这个源码我个人把它分为两大步(暂时我先写出我的总结,后续看是否有时间能写一篇关于debug的过程):

  1. 给我们的Bean,创建与之对应的BeanDefinition,然后把他们放入ConcurrentHashMap(key:beanName和value:beanDefinition)中;BeanDefinition实际上包括一些Bean的信息,比如BeanName, Scope, 是否被@Primary注解修饰,是否是@Lazy,以及@Description等注解
  2. refresh()方法: 创建IOC需要的资源
  • 初始化BeanFactory, set一些属性,如BeanClassLoadersystemEnvironment
  • 如果是SpringBoot程序,会调用方法进行自动装配:AutoConfigurationImportSelector.AutoConfigurationGroup#process,见:@EnableAutoConfiguration的总结
  • 注册MessageSource,国际化相关的资源,到ApplicationContext
  • 注册ApplicationListener到ApplicationContext
  • 实例化化lazy-init的Bean
  • 最后,publish相关的事件,ApplicationContext 就初始化完成,整个IOC容器初始化完成(IOC容器的本质就是初始化BeanFactory和ApplicationContext),就可以从IOC容器中获取Bean自动注入了

SpringApplicationRunListener << EventPublishingRunListener

  1. public class EventPublishingRunListener implements SpringApplicationRunListener, Ordered {
  2. private final SpringApplication application;
  3. private final String[] args;
  4. private final SimpleApplicationEventMulticaster initialMulticaster;
  5. public EventPublishingRunListener(SpringApplication application, String[] args) {
  6. this.application = application;
  7. this.args = args;
  8. this.initialMulticaster = new SimpleApplicationEventMulticaster();
  9. for (ApplicationListener<?> listener : application.getListeners()) {
  10. this.initialMulticaster.addApplicationListener(listener);
  11. }
  12. }
  13. @Override
  14. public int getOrder() {
  15. return 0;
  16. }
  17. // SpringBoot 启动事件
  18. @Override
  19. public void starting(ConfigurableBootstrapContext bootstrapContext) {
  20. this.initialMulticaster
  21. .multicastEvent(new ApplicationStartingEvent(bootstrapContext, this.application, this.args));
  22. }
  23. // 创建和配置环境
  24. @Override
  25. public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
  26. ConfigurableEnvironment environment) {
  27. this.initialMulticaster.multicastEvent(
  28. new ApplicationEnvironmentPreparedEvent(bootstrapContext, this.application, this.args, environment));
  29. }
  30. // 准备ApplicationContext
  31. @Override
  32. public void contextPrepared(ConfigurableApplicationContext context) {
  33. this.initialMulticaster
  34. .multicastEvent(new ApplicationContextInitializedEvent(this.application, this.args, context));
  35. }
  36. // 发布ApplicationContext以及refresh事件,标志着ApplicaitonContext初始化完成
  37. @Override
  38. public void contextLoaded(ConfigurableApplicationContext context) {
  39. for (ApplicationListener<?> listener : this.application.getListeners()) {
  40. if (listener instanceof ApplicationContextAware) {
  41. ((ApplicationContextAware) listener).setApplicationContext(context);
  42. }
  43. context.addApplicationListener(listener);
  44. }
  45. this.initialMulticaster.multicastEvent(new ApplicationPreparedEvent(this.application, this.args, context));
  46. }
  47. // SpringBoot 以启动事件
  48. @Override
  49. public void started(ConfigurableApplicationContext context) {
  50. context.publishEvent(new ApplicationStartedEvent(this.application, this.args, context));
  51. AvailabilityChangeEvent.publish(context, LivenessState.CORRECT);
  52. }
  53. // “SpringBoot现在可以处理接受的请求” 事件
  54. @Override
  55. public void running(ConfigurableApplicationContext context) {
  56. context.publishEvent(new ApplicationReadyEvent(this.application, this.args, context));
  57. AvailabilityChangeEvent.publish(context, ReadinessState.ACCEPTING_TRAFFIC);
  58. }
  59. @Override
  60. public void failed(ConfigurableApplicationContext context, Throwable exception) {
  61. ApplicationFailedEvent event = new ApplicationFailedEvent(this.application, this.args, context, exception);
  62. if (context != null && context.isActive()) {
  63. // Listeners have been registered to the application context so we should
  64. // use it at this point if we can
  65. context.publishEvent(event);
  66. }
  67. else {
  68. // An inactive context may not have a multicaster so we use our multicaster to
  69. // call all of the context's listeners instead
  70. if (context instanceof AbstractApplicationContext) {
  71. for (ApplicationListener<?> listener : ((AbstractApplicationContext) context)
  72. .getApplicationListeners()) {
  73. this.initialMulticaster.addApplicationListener(listener);
  74. }
  75. }
  76. this.initialMulticaster.setErrorHandler(new LoggingErrorHandler());
  77. this.initialMulticaster.multicastEvent(event);
  78. }
  79. }
  80. private static class LoggingErrorHandler implements ErrorHandler {
  81. private static final Log logger = LogFactory.getLog(EventPublishingRunListener.class);
  82. @Override
  83. public void handleError(Throwable throwable) {
  84. logger.warn("Error calling ApplicationEventListener", throwable);
  85. }
  86. }
  87. }

SpringBoot启动流程总结

  • 初始化环境
  • 初始化默认配置
  • 初始化各类监听器、事件
  • 创建上下文
  • 在上下文中添加默认的bean
  • 扫描文件、注解等各种类型的bean添加在上下文中
  • 实例化各个bean
  • 启动完毕

参考资料

【从入门到放弃-SpringBoot】SpringBoot源码分析-启动

https://nc2era.com/97473183.html

SPRINGBOOT启动流程及其原理

https://www.cnblogs.com/theRhyme/p/11057233.html

SPRINGBOOT启动原理(基于2.3.9.RELEASE版本)

https://www.cnblogs.com/theRhyme/p/how-does-springboot-start.html

Spring Boot 2.5.4 API

https://docs.spring.io/spring-boot/docs/2.5.4/api/

spring boot profile配置和启动时no active profile set, falling back to default profiles: default的问题

https://blog.csdn.net/benbenniaono1/article/details/105632264