在run方法中可以看到它进行了SpringApplication的构造,对于SpringApplication的构造函数的分析十分重要。本节将对SpringApplication构造方法进行分析,具体的构造函数代码如下:
在SpringApplication的构造方法中主要的处理流程如下:
(1)设置资源加载器;
(2)设置主要启动类;
(3)设置Web应用类型标记;
(4)获取BootstrapRegistryInitializer集合并设置给成员变量bootstrapRegistryInitializers;
(5)获取ApplicationContextInitializer集合并设置给成员变量initializers;
(6)获取ApplicationListener集合并设置给成员变量listeners;
(7)设置应用类。
在启动SampleWebStaticApplication时通过构造函数创建的SpringApplication成员变量的数据信息如图2-1所示。
在构造函数中会对成员变量initializers进行初始化,在本例中初始化的成员变量initializers的具体数据表如图2-2所示。
在构造函数中还对成员变量listeners进行了初始化,在本例中成员变量listeners的数据信息如图2-3所示。
图2-1 SpringApplication成员变量的数据信息
图2-2 initializers的具体数据表
图2-3 listeners的数据信息
在SpringApplication的构造方法中引用了4个方法,接下来对这4个方法进行分析:
(1)WebApplicationType.deduceFromClasspath方法用于确定Web应用类型标记;
(2)getBootstrapRegistryInitializersFromSpringFactories方法用于获取BootstrapRegistryInitializer集合;
(3)getSpringFactoriesInstances方法用于获取Spring工厂实例;
(4)deduceMainApplicationClass方法用于推到核心应用类。
本节将对WebApplicationType.deduceFromClasspath方法进行分析,具体处理代码如下:
static WebApplicationType deduceFromClasspath() { if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } for (String className :SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } return WebApplicationType.SERVLET; }
在deduceFromClasspath方法中会得到Web应用的类型,在这个处理过程中包含3种类型:
(1)响应式REACTIVE;
(2)非Web应用;
(3)Servlet应用。
在该方法中主要的判断依据是ClassUtils.isPresent方法,isPersent方法调用还需要依靠以下4个成员变量:
(1)WEBFLUX_INDICATOR_CLASS;
(2)WEBMVC_INDICATOR_CLASS;
(3)JERSEY_INDICATOR_CLASS;
(4)SERVLET_INDICATOR_CLASSES。
本节将对getBootstrapRegistryInitializersFromSpringFactories方法进行分析,该方法主要用于获取Bootstrapper和BootstrapRegistryInitializer相关的工厂接口,具体处理代码如下:
在getBootstrapRegistryInitializersFromSpringFactories方法中的处理流程如下:
(1)通过getSpringFactoriesInstances方法将Bootstrapper类型对应的工厂检索到;
(2)将检索到的Bootstrapper类型的工厂遍历调用initialize方法后放入返回集合中;
(3)通过getSpringFactoriesInstances方法将BootstrapRegistryInitializer类型的工厂寻找出来放入返回集合中;
(4)返回结果集合。
本节将对getSpringFactoriesInstances方法进行分析,该方法用于搜索工厂接口,具体处理代码如下:
在上述代码中主要的处理流程如下:
(1)获取类加载器;
(2)获取类型对应的名称集合,这部分数据在META-INF/spring.factories文件中;
(3)通过名称、类型和参数等进行实例化;
(4)将实例化结果进行排序后返回,排序需要依赖Order相关内容。
本节将对createSpringFactoriesInstances方法进行分析,具体处理代码如下:
createSpringFactoriesInstances方法主要目的是将方法参数names进行实例化,具体实例化步骤如下:
(1)通过类加载器根据参数names中的元素获取类对象;
(2)通过第(1)步中获取的类对象进一步获取构造函数对象;
(3)通过BeanUtils进行实例化;
(4)放入数据集合(变量instances)。
本节将对deduceMainApplicationClass方法进行分析,该方法用于确认主类,具体处理代码如下:
private Class<?> deduceMainApplicationClass() { try { // 提取当前堆栈 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement :stackTrace) { // 找到main函数所在的类 if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) {} return null; }
在deduceMainApplicationClass方法中主要的处理流程如下:
(1)获取当前调用堆栈;
(2)遍历当前堆栈集合,如果方法名称是main则会作为最终返回结果。
至此,对于SpringApplication的构造方法分析就告一段落,下一节将开始着重分析run方法。