欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Spring Boot 2.1.1.RELEASE Main方法启动详解一

程序员文章站 2022-05-29 18:33:55
...

一、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