分析下面的代码,底层都做了哪些事情:
new SpringApplication(App.class)
public SpringApplication(Class<?>... primarySources) {this(null, primarySources);
}
初始化SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {this.resourceLoader = resourceLoader;Assert.notNull(primarySources, "PrimarySources must not be null");// 将我们定义的主启动类 "MyApplication.class" 放到 primarySources 中(这样SpringBoot就知道了主启动类是什么,在哪里)this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));// 1、推断应用环境this.webApplicationType = WebApplicationType.deduceFromClasspath();// 在SpringBoot2.4.0之后引入BootstrapRegistryInitializer(目前没有相关实现类)this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));// 2、设置应用初始化器setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));// 3、设置SpringBoot全局监听器setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));// 4、确定主启动类this.mainApplicationClass = deduceMainApplicationClass();
}
推断应用环境
this.webApplicationType = WebApplicationType.deduceFromClasspath()
会从当前应用的类路径下,尝试寻找一些特定的类,并以此推断当前应用更适合哪种web环境。(赋值给 SpringApplication 的成员属性:WebApplicationType webApplicationType)
public enum WebApplicationType {NONE,SERVLET,REACTIVE;private static final String[] SERVLET_INDICATOR_CLASSES = { "javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext" };private static final String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";private static final String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";private static final String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";static WebApplicationType deduceFromClasspath() {// 如果存在 org.springframework.web.reactive.DispatcherHandler && 不存在 org.springframework.web.servlet.DispatcherServlet,则推断为 REACTIVE 环境if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {return WebApplicationType.REACTIVE;}// 如果 "javax.servlet.Servlet" 和 "org.springframework.web.context.ConfigurableWebApplicationContext" 当中有任何一个不存在(若返回 SERVLET 环境会不安全),则推断为 NONE 环境for (String className : SERVLET_INDICATOR_CLASSES) {if (!ClassUtils.isPresent(className, null)) {return WebApplicationType.NONE;}}// 返回 SERVLET 环境return WebApplicationType.SERVLET;}
}
当我们引入的是spring-boot-starter-web 依赖,那么SpringBoot启动的就是 Servlet
环境
当我们引入的是spring-boot-starter-webflux 依赖,那么SpringBoot启动的就是 Reactive
环境
如果都没有依赖,那么SpringBoot启动的就是 None
环境(没有web概念)
设置应用初始化器
setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class))
利用Spring的SPI机制,从项目类路径下 META-INF/spring.factories 中加载所有的 ApplicationContextInitializer
,反射创建对象 (利用无参构造创建对象)
(赋值给 SpringApplication 的成员属性:List<ApplicationContextInitializer<?>> initializers)
共有下面 7 个 ApplicationContextInitializer 被加载(经过Order 排序后):
org.springframework.boot.context.config.DelegatingApplicationContextInitializer
org.springframework.boot.autoconfigure.SharedMetadataReaderFactoryContextInitializer
org.springframework.boot.context.ContextIdApplicationContextInitializer
org.springframework.boot.context.ConfigurationWarningsApplicationContextInitializer
org.springframework.boot.rsocket.context.RSocketPortInfoApplicationContextInitializer
org.springframework.boot.web.context.ServerPortInfoApplicationContextInitializer
org.springframework.boot.autoconfigure.logging.ConditionEvaluationReportLoggingListener
设置应用监听器
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class))
利用Spring的SPI机制,从项目类路径下 META-INF/spring.factories 中加载所有的 ApplicationListener
,反射创建对象
(赋值给 SpringApplication 的成员属性:List<ApplicationListener<?>> listeners)
共有下面 8 个 ApplicationListener 被加载(经过 Order 排序后):
org.springframework.boot.env.EnvironmentPostProcessorApplicationListener
org.springframework.boot.context.config.AnsiOutputApplicationListener
org.springframework.boot.context.logging.LoggingApplicationListener
org.springframework.boot.autoconfigure.BackgroundPreinitializer
org.springframework.boot.context.config.DelegatingApplicationListener
org.springframework.boot.builder.ParentContextCloserApplicationListener
org.springframework.boot.ClearCachesApplicationListener
org.springframework.boot.context.FileEncodingApplicationListener
确定主启动类
this.mainApplicationClass = deduceMainApplicationClass()
推断出主启动类的类对象(即MyApplication的类对象)
(赋值给 SpringApplication 的成员属性:Class<?> mainApplicationClass)
private Class<?> deduceMainApplicationClass() {try {StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); // stackTrace中保存的就是方法调用栈的信息(使用idea的debug窗口观察函数调用栈看看)for (StackTraceElement stackTraceElement : stackTrace) {// 直到遍历到 main 方法所对应的栈帧if ("main".equals(stackTraceElement.getMethodName())) {// 返回的就是主启动类的类对象 Class@1338 class com.itheima.MyApplication return Class.forName(stackTraceElement.getClassName());}}}catch (ClassNotFoundException ex) {// Swallow and continue}return null;
}
总结
经过第一步 SpringApplication 构造方法的处理,创建了 SpringApplication 对象, 初始化了它的以下成员属性
private ResourceLoader resourceLoader;
private Set<Class<?>> primarySources;
private WebApplicationType webApplicationType;
private List<BootstrapRegistryInitializer> bootstrapRegistryInitializers;
private List<ApplicationContextInitializer<?>> initializers;
private List<ApplicationListener<?>> listeners;
private Class<?> mainApplicationClass;