Spring Boot 2.1.1.RELEASE Main方法启动详解一
一、SpringApplication(ResourceLoader, Class<?>...)分析:
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) { // resourceLoader 默认为空(null) this.resourceLoader = resourceLoader; // main方法中的args参数,可接收命令行启动时添加的参数 this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources)); // 1.根据classpath下是否有相应的类确定Spring容器类型 this.webApplicationType = WebApplicationType.deduceFromClasspath(); // 2.加载ApplicationContextInitializer初始化类 setInitializers((Collection) getSpringFactoriesInstances( ApplicationContextInitializer.class)); // 3.加载ApplicationListener监听器 setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); // 4.推断main方法所在的类 this.mainApplicationClass = deduceMainApplicationClass(); }
1.1 确定Spring容器类型
static WebApplicationType deduceFromClasspath() { // 1.确定reactive容器类型 if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; } // 2.确定none容器类型 for (String className : SERVLET_INDICATOR_CLASSES) { if (!ClassUtils.isPresent(className, null)) { return WebApplicationType.NONE; } } // 3.默认servlet容器类型 return WebApplicationType.SERVLET; }
分析:
- 判断,如果能加载org.springframework.web.reactive.DispatcherHandler,并且不能加载org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer,那么判断这个容器类型为WebApplicationType.REACTIVE
- 判断,如果不能加载javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext,那么判断这个容器类型为WebApplicationType.NONE
- 如果前面都没加载,那么容器类型为默认的WebApplicationType.SERVLET
1.2 加载ApplicationContextInitializer初始化类
public void setInitializers(Collection<? extends ApplicationContextInitializer<?>> initializers) { this.initializers = new ArrayList<>(); // 添加ApplicationContextInitializer类 this.initializers.addAll(initializers); }
分析:
通过SpringFactoriesLoader.loadFactoryNames(type, classLoader)加载类名,使用ClassUtils.forName(name, classLoader)加载类对象,并获取构造Constructor方法,使用BeanUtils.instantiateClass(constructor, args)实例化对象,使用AnnotationAwareOrderComparator.sort(instances)进行排序,
他们分别是:
- ConfigurationWarningsApplicationContextInitializer
- ContextIdApplicationContextInitializer
- ConditionEvaluationReportLoggingListener
- SharedMetadataReaderFactoryContextInitializer
- ServerPortInfoApplicationContextInitializer
- DelegatingApplicationContextInitializer
1.3 加载ApplicationListener监听器
public void setListeners(Collection<? extends ApplicationListener<?>> listeners) { this.listeners = new ArrayList<>(); // 添加ApplicationListener类 this.listeners.addAll(listeners); }
分析:
通过SpringFactoriesLoader.loadFactoryNames(type, classLoader)加载类名,使用ClassUtils.forName(name, classLoader)加载类对象,并获取构造Constructor方法,使用BeanUtils.instantiateClass(constructor, args)实例化对象,使用AnnotationAwareOrderComparator.sort(instances)进行排序,
他们分别是:
- BackgroundPreinitializer
- ClearCachesApplicationListener
- ParentContextCloserApplicationListener
- FileEncodingApplicationListener
- AnsiOutputApplicationListener
- ConfigFileApplicationListener
- DelegatingApplicationListener
- ClasspathLoggingApplicationListener
- LoggingApplicationListener
- LiquibaseServiceLocatorApplicationListener
1.4 获取main方法所在类
private Class<?> deduceMainApplicationClass() { try { StackTraceElement[] stackTrace = new RuntimeException().getStackTrace(); // 遍历所有执行过的栈信息,查找到其方法名为mian的栈信息,并返回其类信息 for (StackTraceElement stackTraceElement : stackTrace) { if ("main".equals(stackTraceElement.getMethodName())) { return Class.forName(stackTraceElement.getClassName()); } } } catch (ClassNotFoundException ex) { // Swallow and continue } return null; }
分析:
通过异常获取当前线程的堆栈信息,遍历获取方法名为main的堆栈对应的class信息
注:上面加载类名的读取路径是:/META-INF/spring.factories