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

posted @ 2019-08-16 14:26  张界  阅读(700)  评论(0编辑  收藏  举报