兄弟们跟我来,在入口出打上断点,开始DEBUG:
image.png
stepinto进入SpringApplication
image.png
接下来stepinto会提示我们选择进入SpringApplication构造器还是进入run()方法,IDEA会把他们以紫色标出
image.png

写在前面

创建SpringApplication干了哪些事:先说结论:

  1. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  2. this.resourceLoader = resourceLoader;
  3. Assert.notNull(primarySources, "PrimarySources must not be null");
  4. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  5. this.webApplicationType = WebApplicationType.deduceFromClasspath();
  6. this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
  7. setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
  8. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  9. this.mainApplicationClass = deduceMainApplicationClass();
  10. }
  • primarySources:保存当前主启动类信息class com.atguigu.boot.Boot09HelloTestApplication
  • webApplicationType:使用工具类ClassUtils判定当前应用的类型。一般是Servlet类型,非Reactive类型
  • bootstrappers:初始启动引导器List:去spring.factories文件中找 org.springframework.boot.Bootstrapper
  • setInitializers:ApplicationContextInitializer:去spring.factories找 ApplicationContextInitializer
    • List> initializers
  • setListeners:ApplicationListener:去spring.factories找 ApplicationListener
    • List> listeners

image.png
倘若stepinto的这一行代码有多个函数(构造方法也是函数),则IDEA会提示我们选择进入SpringApplication构造器还是进入run()方法,IDEA会把他们以紫色标出,由于这里我们分析SpringApplication创建,所以我们选择进入SpringApplication构造器,点机SpringApplication,来到了这,调用this构造器
image.png
接着stepinto,来到了SpringApplication构造器,我们一步步stepout,跳过类的变量初始化,这是个赋初始默认值的过程
最后终于进入了SpringApplication构造器当中的第一行代码
image.png
image.png
image.png

this.primarySources

SpringApplication构造器方法当中stepout到这,this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
给主资源this.primarySources赋值,就是我们的主类class com.atguigu.boot.Boot09HelloTestApplication
image.png

this.webApplicationType

接下来我们stepinto进this.webApplicationType = WebApplicationType.deduceFromClasspath();看看做了什么事情
使用ClassUtils工具类,会先判断我们的应用是响应式reactiveorg.springframework.web.reactive.DispatcherHandler,发现不是
我们的应用是servlet的,所以最终会返回return WebApplicationType.SERVLET;
image.png
一行行stepout,我们最终跳出static WebApplicationType deduceFromClasspath() {}方法,返回到上一级,
发现SpringApplication构造器中的this.webApplicationType终于赋到了值,为SERVLET
image.png

this.bootstrappers

下面我们stepout,this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
给初始启动引导器(List)赋值,赋值为空,我们先不管
image.png

setInitializers

下面我们stepout,setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));会去找 ApplicationContextInitializer;
去spring.factories找 ApplicationContextInitializer,最终赋值给SpringApplication类的变量,,this.initializers,size=8

  1. List<ApplicationContextInitializer<?>> initializers.size=8

image.png
debug栏的this代表当前SpringApplication构造器,展开this,会印证this.initializers.size=8
image.png

关于setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));具体做了什么事呢? stepinto看看

image.png

image.png

image.png

image.png
发现它还是从"META-INF/spring.factories"加载所谓的ApplicationContextInitializer
发现spring-boot-2.4.0.jar下有5个Initializer

  1. # Application Context Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
  4. org.springframework.boot.context.ContextIdApplicationContextInitializer,\
  5. org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
  6. org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
  7. org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer

发现spring-boot-autoconfigure-2.3.4.RELEASE.jar下有2个Initializer

  1. # Initializers
  2. org.springframework.context.ApplicationContextInitializer=\
  3. org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
  4. org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener

加起来一共7个ApplicationContextInitializer

setListeners

接着stepout,setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
会去找ApplicationListener ;应用监听器。去spring.factories找 ApplicationListener,赋值给SpringApplication类的变量this.listeners,size=10

  1. private List<ApplicationListener<?>> listeners;

image.png
image.png
同理,发现它还是从"META-INF/spring.factories"加载所谓的ApplicationListener ;应用监听器
发现spring-boot-2.4.0.jar下有9个ApplicationListener

  1. # Application Listeners
  2. org.springframework.context.ApplicationListener=\
  3. org.springframework.boot.ClearCachesApplicationListener,\
  4. org.springframework.boot.builder.ParentContextCloserApplicationListener,\
  5. org.springframework.boot.context.FileEncodingApplicationListener,\
  6. org.springframework.boot.context.config.AnsiOutputApplicationListener,\
  7. org.springframework.boot.context.config.DelegatingApplicationListener,\
  8. org.springframework.boot.context.logging.LoggingApplicationListener,\
  9. org.springframework.boot.env.EnvironmentPostProcessorApplicationListener,\
  10. org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener

发现spring-boot-autoconfigure-2.3.4.RELEASE.jar下有1个ApplicationListener

  1. # Application Listeners
  2. org.springframework.context.ApplicationListener=\
  3. org.springframework.boot.autoconfigure.BackgroundPreinitializer

加起来一共10个ApplicationContextInitializer

this.mainApplicationClass

接着stepout,this.mainApplicationClass = deduceMainApplicationClass();,找我们的主程序,我们stepinto看看
deduceMainApplicationClass()的大概逻辑:找到第一个带有main方法的程序,就是我们的主程序
image.png
image.png
stepout结束返回:
image.png
stepout结束再返回:
image.png
stepout结束再返回:
image.png
到这里,再stepinto就轮到run()方法啦,即运行SpringApplication的分析啦,我们下期再见!