springboot启动原理篇一:SpringApplication的初始化

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));
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    this.mainApplicationClass = deduceMainApplicationClass();
}
  • 进入SpringApplication构造器SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources)中,首先SpringApplication.resourceLoader赋值null

    this.resourceLoader = resourceLoader;
    
  • 将主启动类加入到 SpringApplication.primarySources

    // 存储主要的应用程序源,即用于启动 Spring Boot 应用程序的主要配置类或主类,这个主类通常是我们springboot项目的启动类
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    
  • 判断应用类型,并赋值给 SpringApplication.webApplicationType

    // 获取应用程序的 Web 应用类型,并赋值给SpringApplication.webApplicationType
    this.webApplicationType = WebApplicationType.deduceFromClasspath();
    
    • deduceFromClasspath()方法源码如下

      String[] SERVLET_INDICATOR_CLASSES = {"javax.servlet.Servlet","org.springframework.web.context.ConfigurableWebApplicationContext"};
      String WEBMVC_INDICATOR_CLASS = "org.springframework.web.servlet.DispatcherServlet";
      String WEBFLUX_INDICATOR_CLASS = "org.springframework.web.reactive.DispatcherHandler";
      String JERSEY_INDICATOR_CLASS = "org.glassfish.jersey.servlet.ServletContainer";
      
      static WebApplicationType deduceFromClasspath() {
          if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) // 判断DispatcherHandler类是否存在于类路径中
              && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null) // 判断DispatcherServlet类是否存在于类路径中
              && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) { // 判断ServletContainer类是否存在于类路径中
              return WebApplicationType.REACTIVE; // 返回响应式的spring应用
          }
          for (String className : SERVLET_INDICATOR_CLASSES) {
              // 判断Servlet和ConfigurableWebApplicationContext是否存在于类路径中
              if (!ClassUtils.isPresent(className, null)) {
                  return WebApplicationType.NONE;
              }
          }
          return WebApplicationType.SERVLET;// 基于servlet的spring应用
      }
      
  • 调用getSpringFactoriesInstances方法,传入 BootstrapRegistryInitializer.class作为参数将 并赋值给 SpringApplication.bootstrapRegistryInitializers

    // 初始化引导注册表(Bootstrap Registry)的初始化器列表
    this.bootstrapRegistryInitializers = new ArrayList<>(getSpringFactoriesInstances(BootstrapRegistryInitializer.class));
    
    • getSpringFactoriesInstances()源码

      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();
          // 将list集合转换为set
          Set<String> names = new LinkedHashSet<>(SpringFactoriesLoader.loadFactoryNames(type, classLoader));
          // 实例化所有names中的类,装到list中返回
          List<T> instances = createSpringFactoriesInstances(type, parameterTypes, classLoader, args, names);
          AnnotationAwareOrderComparator.sort(instances);
          return instances;
      }
      
      • SpringFactoriesLoader.loadFactoryNames(type, classLoader)源码

        public static List<String> loadFactoryNames(Class<?> factoryType, @Nullable ClassLoader classLoader) {
            ClassLoader classLoaderToUse = classLoader;
            if (classLoaderToUse == null) {
                classLoaderToUse = SpringFactoriesLoader.class.getClassLoader();
            }
            String factoryTypeName = factoryType.getName();
            // loadSpringFactories返回的是所有配置,调用getOrDefault,从配置中抽取对应的key-value并返回value(这个value是个list)
            return loadSpringFactories(classLoaderToUse).getOrDefault(factoryTypeName, Collections.emptyList());
        }
        
        • loadSpringFactories源码

          // 加载spring.factories文件中的全部配置(代码看一下即可,不必深究)
          private static Map<String, List<String>> loadSpringFactories(ClassLoader classLoader) {
              Map<String, List<String>> result = cache.get(classLoader);
              if (result != null) {
                  return result;
              }
              result = new HashMap<>();
              try {
                  //读取META-INFO/spring.factories文件中的配置
                  Enumeration<URL> urls = classLoader.getResources(FACTORIES_RESOURCE_LOCATION);
                  while (urls.hasMoreElements()) {
                      URL url = urls.nextElement();
                      UrlResource resource = new UrlResource(url);
                      Properties properties = PropertiesLoaderUtils.loadProperties(resource);
                      for (Map.Entry<?, ?> entry : properties.entrySet()) {
                          String factoryTypeName = ((String) entry.getKey()).trim();
                          String[] factoryImplementationNames = StringUtils.commaDelimitedListToStringArray((String) entry.getValue());
                          for (String factoryImplementationName : factoryImplementationNames) {
                              result.computeIfAbsent(factoryTypeName, key -> new ArrayList<>()).add(factoryImplementationName.trim());
                          }
                      }
                  }
                  // Replace all lists with unmodifiable lists containing unique elements
                  result.replaceAll((factoryType, implementations) -> implementations.stream().distinct().collect(Collectors.collectingAndThen(Collectors.toList(), Collections::unmodifiableList)));
                  cache.put(classLoader, result);
              }
              catch (IOException ex) {
                  throw new IllegalArgumentException("Unable to load factories from location [" +
                                                     FACTORIES_RESOURCE_LOCATION + "]", ex);
              }
              return result;
          }
          
      • createSpringFactoriesInstances()源码

        // 由传递可知,parameterTypes是个空集合,也就意味着获取的类的构造器是无参构造器(这里需要你拥有Java反射的知识)
        private <T> List<T> createSpringFactoriesInstances(Class<T> type,
                                                           Class<?>[] parameterTypes,
                                                           ClassLoader classLoader,
                                                           Object[] args,
                                                           Set<String> names) {
        	// 初始化一个list,用于存放实例对象
            List<T> instances = new ArrayList<>(names.size());
            // 遍历list,这个names就是getSpringFactoriesInstances中调用此方法传入的类集合
            for (String name : names) {
                try {
                    Class<?> instanceClass = ClassUtils.forName(name, classLoader);//找到此类
                    Assert.isAssignable(type, instanceClass);
                    Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);//获取此类的构造器
                    T instance = (T) BeanUtils.instantiateClass(constructor, args);//利用获取到的构造器实例化类的对象
                    instances.add(instance);// 将实例化对象加入到instances中
                }
                catch (Throwable ex) {
                    throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
                }
            }
            return instances;// 返回存放实例对象的list
        }
        
  • 调用getSpringFactoriesInstances方法,传入ApplicationContextInitializer.class作为参数 并赋值给SpringApplication.initializers

    // 获取所有实现了 ApplicationContextInitializer 接口的初始化器实例,并将它们设置为应用程序的初始化器(initializers)。这些初始化器在应用程序启动时执行特定的初始化逻辑,例如配置属性源、设置环境变量等
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    
  • 调用getSpringFactoriesInstances方法,传入 ApplicationListener.class作为参数将 并赋值给 SpringApplication.Listeners

    // 获取所有实现了 ApplicationListener 接口的监听器实例,并将它们设置为应用程序的监听器(listeners)。这些监听器用于监听和响应应用程序的各种事件,例如应用程序启动事件、环境准备事件等
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    
  • 将主启动类赋值给 SpringApplication.mainApplicationClass

    // 推断并设置应用程序的主类(main class),用于识别应用程序的入口点
    this.mainApplicationClass = deduceMainApplicationClass();
    

总结

SpringApplication的初始化工作主要干了以下几件事

  1. 为resourceLoader赋值为null,
  2. 设置primarySources为当前项目运行启动类
  3. 判断应用类型,并赋值给webApplicationType
  4. 实例化“初始化引导注册表(bootstrapRegistryInitializers)”的初始化器列表,这个列表中存的是实例化的实现了BootstrapRegistryInitializer.class接口的类的对象。
  5. 实例化“应用程序的初始化器(Initializer)”的初始化器列表,这个列表中存的是实例化的实现了ApplicationContextInitializer.class接口的类的对象
  6. 实例化“监听器(listeners)”的列表,这个列表中存的是实例化的实现了ApplicationListener.class接口的类的对象
  7. 为mainApplicationClass属性赋值,值为应用程序的入口点,一般是我们springboot项目的启动类

最近忙着面试,时间仓促,就先把执行流程先捋一遍,后面有空了,再详细解释每步的作用和意义,再画个流程图来解释整个流程

posted @   勤匠  阅读(31)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示