兄弟们跟我来,在入口出打上断点,开始DEBUG:
stepinto进入SpringApplication
接下来stepinto会提示我们选择进入SpringApplication
构造器还是进入run()
方法,IDEA会把他们以紫色标出
写在前面
创建SpringApplication
干了哪些事:先说结论:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
this.webApplicationType = WebApplicationType.deduceFromClasspath();
this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
this.mainApplicationClass = deduceMainApplicationClass();
}
- 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
- List
- setListeners:
ApplicationListener
:去spring.factories找 ApplicationListener- List
> listeners
- List
倘若stepinto的这一行代码有多个函数(构造方法也是函数),则IDEA会提示我们选择进入SpringApplication
构造器还是进入run()
方法,IDEA会把他们以紫色标出,由于这里我们分析SpringApplication
创建,所以我们选择进入SpringApplication
构造器,点机SpringApplication
,来到了这,调用this构造器
接着stepinto,来到了SpringApplication
构造器,我们一步步stepout,跳过类的变量初始化,这是个赋初始默认值的过程
最后终于进入了SpringApplication
构造器当中的第一行代码
this.primarySources
在SpringApplication
构造器方法当中stepout到这,this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
给主资源this.primarySources
赋值,就是我们的主类class com.atguigu.boot.Boot09HelloTestApplication
this.webApplicationType
接下来我们stepinto进this.webApplicationType = WebApplicationType.deduceFromClasspath();
看看做了什么事情
使用ClassUtils
工具类,会先判断我们的应用是响应式reactive
吗org.springframework.web.reactive.DispatcherHandler
,发现不是
我们的应用是servlet的,所以最终会返回return WebApplicationType.SERVLET;
一行行stepout,我们最终跳出static WebApplicationType deduceFromClasspath() {}
方法,返回到上一级,
发现SpringApplication
构造器中的this.webApplicationType
终于赋到了值,为SERVLET
this.bootstrappers
下面我们stepout,this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
给初始启动引导器(List
setInitializers
下面我们stepout,setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
会去找 ApplicationContextInitializer;
去spring.factories找 ApplicationContextInitializer,最终赋值给SpringApplication
类的变量,,this.initializers,size=8
List<ApplicationContextInitializer<?>> initializers.size=8
debug栏的this代表当前SpringApplication
构造器,展开this,会印证this.initializers.size=8
关于
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
具体做了什么事呢? stepinto看看
发现它还是从"META-INF/spring.factories"
加载所谓的ApplicationContextInitializer
发现spring-boot-2.4.0.jar
下有5个Initializer
# Application Context Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer,\
org.springframework.boot.context.ContextIdApplicationContextInitializer,\
org.springframework.boot.context.config.DelegatingApplicationContextInitializer,\
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer,\
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
发现spring-boot-autoconfigure-2.3.4.RELEASE.jar
下有2个Initializer
# Initializers
org.springframework.context.ApplicationContextInitializer=\
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer,\
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
加起来一共7个ApplicationContextInitializer
setListeners
接着stepout,setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
会去找ApplicationListener ;应用监听器。去spring.factories找 ApplicationListener,赋值给SpringApplication
类的变量this.listeners
,size=10
private List<ApplicationListener<?>> listeners;
同理,发现它还是从"META-INF/spring.factories"
加载所谓的ApplicationListener ;应用监听器
发现spring-boot-2.4.0.jar
下有9个ApplicationListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.ClearCachesApplicationListener,\
org.springframework.boot.builder.ParentContextCloserApplicationListener,\
org.springframework.boot.context.FileEncodingApplicationListener,\
org.springframework.boot.context.config.AnsiOutputApplicationListener,\
org.springframework.boot.context.config.DelegatingApplicationListener,\
org.springframework.boot.context.logging.LoggingApplicationListener,\
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener,\
org.springframework.boot.liquibase.LiquibaseServiceLocatorApplicationListener
发现spring-boot-autoconfigure-2.3.4.RELEASE.jar
下有1个ApplicationListener
# Application Listeners
org.springframework.context.ApplicationListener=\
org.springframework.boot.autoconfigure.BackgroundPreinitializer
加起来一共10个ApplicationContextInitializer
this.mainApplicationClass
接着stepout,this.mainApplicationClass = deduceMainApplicationClass();
,找我们的主程序,我们stepinto看看deduceMainApplicationClass()
的大概逻辑:找到第一个带有main
方法的程序,就是我们的主程序
stepout结束返回:
stepout结束再返回:
stepout结束再返回:
到这里,再stepinto就轮到run()方法啦,即运行SpringApplication
的分析啦,我们下期再见!