zoukankan      html  css  js  c++  java
  • springboot启动逻辑分析(一)-------new SpringApplication()

        public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
            this.resourceLoader = resourceLoader;
            Assert.notNull(primarySources, "PrimarySources must not be null");
            this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources))     
            //(1).根据classpath中的存在的类推断应用类型
         this.webApplicationType = WebApplicationType.deduceFromClasspath();
            //(2).获取ApplicationContextInitializer,并设置到Initializers中
            setInitializers((Collection) getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
           //(3).获取ApplicationContextInitializer,并设置到Initializers中
           setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class)); 
          //(4).推断主类
          this.mainApplicationClass = deduceMainApplicationClass(); 
    }

    调用链路为:

        at org.springframework.boot.SpringApplication.<init>(SpringApplication.java:265)
        at org.springframework.boot.SpringApplication.<init>(SpringApplication.java:249)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248)
        at com.ivy.demo.DemoApplication.main(DemoApplication.java:16)

    (1).推断应用类型

      主要逻辑根据classPath中存在的类,判断应用类型

            this.webApplicationType = WebApplicationType.deduceFromClasspath();
        static WebApplicationType deduceFromClasspath() {
         //springframework.web.reactive.DispatcherHandler类
         //但是不存在org.springframework.web.servlet.DispatcherServlet和org.glassfish.jersey.servlet.ServletContainer类
         //返回WebApplicationType.REACTIVE类型
    if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { return WebApplicationType.REACTIVE; }
         //
    不存在javax.servlet.Servlet和org.springframework.web.context.ConfigurableWebApplicationContext
         //返回WebApplicationType.NONE
         for (String className : SERVLET_INDICATOR_CLASSES) 
         {
           if (!ClassUtils.isPresent(className, null))
           {
             return WebApplicationType.NONE;
           }
         }
       return WebApplicationType.SERVLET;
    }

    2.setInitializers

      主要逻辑是通过classLoader加载所有classPath中的META-INF/spring.factories文件,将加载的key(接口或者子类)-value(接口的实现类)缓存到map中,并返回指定接口的实现类结合

      这里获取的是配置的ApplicationContextInitializer的所有配置的实现类

            setInitializers((Collection) getSpringFactoriesInstances(
                    ApplicationContextInitializer.class));
        private <T> Collection<T> getSpringFactoriesInstances(Class<T> type) {
            return getSpringFactoriesInstances(type, new Class<?>[] {});
        }
       private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
                Class<?>[] parameterTypes, Object... args) {
            ClassLoader classLoader = getClassLoader();
         // (1).获取classPath所有
    META-INF/spring.factories中配置的key为ApplicationContextInitializer的接口
       Set<String> names = new LinkedHashSet<>(
         SpringFactoriesLoader.loadFactoryNames(type, classLoader));
         // (2).初始化所有配置
    ApplicationContextInitializer的接口的实现类
         List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names); 
         AnnotationAwareOrderComparator.sort(instances);
         return instances;
      }
        public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
         //(1).获取class类型名称 String factoryClassName
    = factoryClass.getName();
         //(2).通过classLoader加载所有的META-INF/spring.factories中配置的属性值,并取得需要factoryClassName类型的
         //factoryClassName对应接口的实现类
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList()); }
       private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
            MultiValueMap<String, String> result = cache.get(classLoader);
         //(1).判断当前classLoader是否已经加载过,加载过直接返回
         if (result != null) { return result; } try {
            //(2).获取classPath中所有META-INF/spring.factories,可能需要递归到父classLoader Enumeration
    <URL> urls = (classLoader != null ? classLoader.getResources(FACTORIES_RESOURCE_LOCATION) : ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION)); result = new LinkedMultiValueMap<>();
           //(3).读取所有的url指定文件,保存到以文件中key为key的map(集中同一类型的实现类)
    while (urls.hasMoreElements()) { URL url = urls.nextElement(); UrlResource resource = new UrlResource(url); Properties properties = PropertiesLoaderUtils.loadProperties(resource); for (Map.Entry<?, ?> entry : properties.entrySet()) { String factoryClassName = ((String) entry.getKey()).trim(); for (String factoryName : StringUtils.commaDelimitedListToStringArray((String) entry.getValue())) { result.add(factoryClassName, factoryName.trim()); } } }
           //(4).保存到缓存 cache.put(classLoader, result);
    return result; } catch (IOException ex) { throw new IllegalArgumentException("Unable to load factories from location [" + FACTORIES_RESOURCE_LOCATION + "]", ex); } }

     (3).setListeners

    主要逻辑和(2)类似,只是这里获取的是配置的ApplicationListener的所有配置的实现类

            setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

    (4).deduceMainApplicationClass

    根据调用链接,推断主类(方法中包含‘main’字符串)

            this.mainApplicationClass = deduceMainApplicationClass();
        private Class<?> deduceMainApplicationClass() {
            try {
                StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
                for (StackTraceElement stackTraceElement : stackTrace) {
                    if ("main".equals(stackTraceElement.getMethodName())) {
                        return Class.forName(stackTraceElement.getClassName());
                    }
                }
            }
            catch (ClassNotFoundException ex) {
                // Swallow and continue
            }
            return null;
        }
  • 相关阅读:
    Pair Project: Elevator Scheduler
    Project: Individual Project
    【homework week5】初步了解敏捷开发——自由与约束的哲学统一
    【homework #1】第一次作业被虐感受
    To be transfered
    谈敏捷,谈开发 --《Agile Software Development》读后感
    结对编程---附加题作业(作业请参考相应博客)
    结对编程-电梯调度算法的实现 (附加题部分请参考对应博客)
    必应缤纷桌面的必应助手-软件分析和用户市场需求之-----二.体验部分 Ryan Mao (毛宇11061171) (完整版本请参考团队博客)
    对学长所谓“改变世界的游戏”《shield star》的运行感想-毛宇部分(完整版本请参考团队博客)
  • 原文地址:https://www.cnblogs.com/itivy/p/11665758.html
Copyright © 2011-2022 走看看