上篇文章SpringBoot自动装配原理解析中,我们分析了SpringBoot的自动装配原理以及@SpringBootApplication注解的原理,本篇文章则继续基于上篇文章中的main方法来分析SpringApplication这个类

  1. @SpringBootApplication
  2. public class DemoApplication {
  3. public static void main(String[] args) {
  4. SpringApplication.run(DemoApplication.class, args);
  5. }
  6. }

点击run方法一路跟踪下来,发现首先做的是实例化SpringApplication对象实例

  1. public static ConfigurableApplicationContext run(Class<?> primarySource,
  2. String... args) {
  3. return run(new Class<?>[] { primarySource }, args);
  4. }
  5. public static ConfigurableApplicationContext run(Class<?>[] primarySources,
  6. String[] args) {
  7. return new SpringApplication(primarySources).run(args);
  8. }
  9. public SpringApplication(Class<?>... primarySources) {
  10. this(null, primarySources);
  11. }
  12. public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
  13. this.resourceLoader = resourceLoader;
  14. Assert.notNull(primarySources, "PrimarySources must not be null");
  15. this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
  16. this.webApplicationType = deduceWebApplicationType();
  17. setInitializers((Collection) getSpringFactoriesInstances(
  18. ApplicationContextInitializer.class));
  19. setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
  20. this.mainApplicationClass = deduceMainApplicationClass();
  21. }

deduceWebApplicationType方法

  1. 首先看一下deduceWebApplicationType方法
  1. private WebApplicationType deduceWebApplicationType() {
  2. if (ClassUtils.isPresent("org.springframework.web.reactive.DispatcherHandler", (ClassLoader)null) && !ClassUtils.isPresent("org.springframework.web.servlet.DispatcherServlet", (ClassLoader)null)) {
  3. return WebApplicationType.REACTIVE;
  4. }
  5. for (String className : "javax.servlet.Servlet", org.springframework.web.context.ConfigurableWebApplicationContext") {
  6. if (!ClassUtils.isPresent(className, null)) {
  7. return WebApplicationType.NONE;
  8. }
  9. }
  10. return WebApplicationType.SERVLET;
  11. }
  12. }

大抵意思就是根据当前项目中是否存在上方的几个类来推断出当前的web环境,这里因为SpringBoot默认使用的web框架是SpringMVC,所以最后返回结果为WebApplicationType.SERVLET

ApplicationContextInitializer和ApplicationListener

  1. 加载所有的ApplicationContextInitializerApplicationListener的实现类
  1. private <T> Collection<T> getSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes, Object... args) {
  2. ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
  3. Set<String> names = new LinkedHashSet(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
  4. List<T> instances = this.createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
  5. AnnotationAwareOrderComparator.sort(instances);
  6. return instances;
  7. }

可以看到主要还是用的SpringFactoriesLoader这个类去加载这两个接口的实现类,加载到类以后使用反射的方式构造出这些类的实例,然后根据这些实现类上的Order注解的值进行排序

mainApplicationClass

  1. 最后一行的意义是找到入口方法main所在的类,赋值给全局变量mainApplicationClass
    1. private Class<?> deduceMainApplicationClass() {
    2. try {
    3. StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
    4. for (StackTraceElement stackTraceElement : stackTrace) {
    5. if ("main".equals(stackTraceElement.getMethodName())) {
    6. return Class.forName(stackTraceElement.getClassName());
    7. }
    8. }
    9. }
    10. catch (ClassNotFoundException ex) {
    11. // Swallow and continue
    12. }
    13. return null;
    14. }