zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    短信平台接口调用方法参考
    C#部分类与部分方法
    Oracle表字段类型更改的一个经验
    ueditor的上传文件漏洞(c#)
    判断一个文件是否是指定后缀名的文件
    利用FluorineFx的ByteArray上传图片
    FluorineFx 播放FLV 时堆棧溢出解决 FluorineFx NetStream.play 并发时,无法全部连接成功的解决办法
    Flex数据交互之Remoting[转]
    fluorinefx使用手册
    SharedObject使用:在FluorineFx.net与Flex中使用共享对象维护在线用户列表实例【转】
  • 原文地址:https://www.cnblogs.com/pascall/p/11363680.html
Copyright © 2011-2022 走看看