SpringApplication的创建
基于 2.2.9.RELEASE的版本,启动项目debug
@SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } }
public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) { return new SpringApplication(primarySources).run(args); }
run方法最后的走到SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) 来实例化我们的SpringApplication
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
// 1.1 this.resourceLoader = resourceLoader;
Assert.notNull(primarySources, "PrimarySources must not be null");
// 1.2 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
// 1.3 this.webApplicationType = WebApplicationType.deduceFromClasspath();
// 1.4 setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
// 1.5 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
// 1.6 this.mainApplicationClass = deduceMainApplicationClass(); }
1.1 resourceLoader
属性,资源加载器
此处debug显示为null;感兴趣的小伙伴可以看一看:Spring 统一资源加载策略(https://blog.csdn.net/cuiwjava/article/details/108940768)
1.2 primarySources
属性,主要的 Java Config 类的数组
在此处就是对应我们的启动类 DemoApplication 类。
1.3 webApplicationType
属性,调用 WebApplicationType#deduceFromClasspath()
方法,通过 classpath ,判断 Web 应用类型
static WebApplicationType deduceFromClasspath() {
// WebApplicationType.REACTIVE 类型 if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; }
// WebApplicationType.NONE 类型 for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } }
// WebApplicationType.SERVLET 类型。可以酱紫的判断的原因是,引入 Spring MVC 时,如果是内嵌的 Web 应用,会引入 Servlet 类。 return WebApplicationType.SERVLET; }
1.4 initializers
属性,ApplicationContextInitializer 数组
通过 #getSpringFactoriesInstances(Class<T> type)
方法,进行获得 ApplicationContextInitializer 类型的对象数组。
private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) { ClassLoader classLoader = getClassLoader(); // 1.4.1 加载指定类型对应的,在 `META-INF/spring.factories` 里的类名的数组 Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
// 1.4.2 创建对象们 List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
// 1.4.3 排序对象们 AnnotationAwareOrderComparator.sort(instances); return instances; }
1.4.1,调用 SpringFactoriesLoader#loadFactoryNames(Class<?> factoryClass, ClassLoader classLoader)
方法,加载指定类型对应的,在 META-INF/spring.factories
里的类名的数组。在 META-INF/spring.factories
文件中,会以 KEY-VALUE 的格式,配置每个类对应的实现类们。关于 SpringFactoriesLoader 的该方法,我们就不去细看了。
1.4.2,调用 #createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names)
方法,创建对象们。代码如下:
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, ClassLoader classLoader, Object[] args, Set<String> names) { List<T> instances = new ArrayList<>(names.size()); for (String name : names) { try {
// 获得 name 对应的类 Class<?> instanceClass = ClassUtils.forName(name, classLoader);
// 判断类是否实现自 type 类 Assert.isAssignable(type, instanceClass);
// 获得构造方法 Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
// 创建对象 T instance = (T) BeanUtils.instantiateClass(constructor, args); instances.add(instance); } catch (Throwable ex) { throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex); } } return instances; }
1.4.3,调用 AnnotationAwareOrderComparator#sort(List<?> list) 方法,排序对象们。例如说,类上有 @Order 注解。
当前Demo是在 Spring MVC 的环境下,initializers
属性的结果如下图:
1.5 listeners
属性,ApplicationListener 数组
也是通过 #getSpringFactoriesInstances(Class<T> type)
方法,进行获得 ApplicationListener 类型的对象数组。listeners
属性的结果如下图:
1.6 mainApplicationClass
属性
调用 #deduceMainApplicationClass()
方法,获得是调用了哪个 #main(String[] args)
方法,代码如下:
private Class<?> deduceMainApplicationClass() { try {
// 获得当前 StackTraceElement 数组 StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); for (StackTraceElement stackTraceElement : stackTrace) {
// 判断哪个执行了 main 方法 if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
此处对应的就是我们Demo的启动类,DemoApplication,到处我们SpringApplication创建完成。代码不是很复杂,主要部分是加载META-INF/spring.factories里面的资源并实例化。