SpringBoot启动类的代码底层原理第一步

本文详细剖析了SpringBoot启动过程中的关键步骤,包括资源加载器初始化、启动类配置信息存储、web环境类型推断、初始化器及监听器的设置等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先我们来看一段代码,SpringBoot启动类:

public static void main(String[] args) {        
  SpringApplication.run(StudentApplication.class);
}

只有一行代码,却完成了ssm中大量配置才能完成的事情,这一行代码中的一个方法究竟做了什么事情。

在我们该类之后,大致做了两件事,一是SpringApplication初始化,二是SpringApplication.run()启动

public static ConfigurableApplicationContext run(Class<?> primarySource,
      String... args) {
    return run(new Class<?>[] { primarySource }, args);
  }

调用静态方法初始化SpringApplication,然后启动运行

public static ConfigurableApplicationContext run(Class<?>[] primarySources,
      String[] args) {
    return new SpringApplication(primarySources).run(args);
  }

初始化方法底层代码

public SpringApplication(Class<?>... primarySources) {
    this(null, primarySources);
  }
  
 public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    //初始化资源加载器
    this.resourceLoader = resourceLoader;
    Assert.notNull(primarySources, "PrimarySources must not be null");
    //将启动类的配置信息存储在集合中
    this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
    //推断web环境的类型(reactive,none,servlet)
    this.webApplicationType = deduceWebApplicationType();
    //设置初始化器 从配置文件spring.factories中查找所有的key=org.springframework.context.ApplicationContextInitializer的类【加载,初始化,排序】
    setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));
    //设置监听器 从配置文件spring.factories中查找所有的key=org.springframework.context.ApplicationListener的类.【加载,初始化,排序】
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
    //推断main方法定义的类
    this.mainApplicationClass = deduceMainApplicationClass();
  }

1.初始化资源加载器

this.resourceLoader = resourceLoader;

2.将启动类的信息存储在集合中

this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));

​3.推断web环境的类型(reactive,none,servlet)

private WebApplicationType deduceWebApplicationType() {
    if (ClassUtils.isPresent(REACTIVE_WEB_ENVIRONMENT_CLASS, null)
        && !ClassUtils.isPresent(MVC_WEB_ENVIRONMENT_CLASS, null)) {
      return WebApplicationType.REACTIVE;
    }
    for (String className : WEB_ENVIRONMENT_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
        return WebApplicationType.NONE;
      }
    }
    return WebApplicationType.SERVLET;
 }

  4.设置初始化器

setInitializers((Collection) getSpringFactoriesInstances(
        ApplicationContextInitializer.class));

底层代码

private <T> Collection<T> getSpringFactoriesInstances(Class<T> type,
      Class<?>[] parameterTypes, Object... args) {
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    // Use names and ensure unique to protect against duplicates
   // 使用Set保存names来避免重复元素
    Set<String> names = new LinkedHashSet<>(
        SpringFactoriesLoader.loadFactoryNames(type, classLoader));
    // 通过上面获取到的类的全限定名,这里将会使用Class.forName加载类,并调用构造方法实例化类
    List<T> instances = createSpringFactoriesInstances(type, parameterTypes,
        classLoader, args, names);
    // 对实例进行排序
    AnnotationAwareOrderComparator.sort(instances);
    return instances;
  }
  
    public static final String FACTORIES_RESOURCE_LOCATION = "META-INF/spring.factories";
    
    //类方法加载的过程
  public static List<String> loadFactoryNames(Class<?> factoryClass, @Nullable ClassLoader classLoader) {
    String factoryClassName = factoryClass.getName();
    return loadSpringFactories(classLoader).getOrDefault(factoryClassName, Collections.emptyList());
  }


  private static Map<String, List<String>> loadSpringFactories(@Nullable ClassLoader classLoader) {
    MultiValueMap<String, String> result = cache.get(classLoader);
    if (result != null) {
      return result;
    }


    try {
    //从类路径的META-INF/spring.factories中加载所有默认的自动配置类
      Enumeration<URL> urls = (classLoader != null ?
          classLoader.getResources(FACTORIES_RESOURCE_LOCATION) :
          ClassLoader.getSystemResources(FACTORIES_RESOURCE_LOCATION));
      result = new LinkedMultiValueMap<>();
      //遍历加载出来的类路径
      while (urls.hasMoreElements()) {
        URL url = urls.nextElement();
        UrlResource resource = new UrlResource(url);
        Properties properties = PropertiesLoaderUtils.loadProperties(resource);
        for (Map.Entry<?, ?> entry : properties.entrySet()) {
          List<String> factoryClassNames = Arrays.asList(
              StringUtils.commaDelimitedListToStringArray((String) entry.getValue()));
          result.addAll((String) entry.getKey(), factoryClassNames);
        }
      }
      cache.put(classLoader, result);
      return result;
    }
    catch (IOException ex) {
      throw new IllegalArgumentException("Unable to load factories from location [" +
          FACTORIES_RESOURCE_LOCATION + "]", ex);
    }
  }

META-INF/spring.factories,如图示:

执行完之后:

5.设置监听器

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

具体的方式和上面初始化器相同。

6.推断mian()自定义的类

this.mainApplicationClass = deduceMainApplicationClass();

底层

private Class<?> deduceMainApplicationClass() {
    try {
     //获取栈帧
      StackTraceElement[] stackTrace = new RuntimeException().getStackTrace();
      for (StackTraceElement stackTraceElement : stackTrace) {
        // 通过main的栈帧推断出入口类的名字
        if ("main".equals(stackTraceElement.getMethodName())) {
          return Class.forName(stackTraceElement.getClassName());
        }
      }
    }
    catch (ClassNotFoundException ex) {
      // Swallow and continue
    }
    return null;
  }

获取栈帧

循环遍历得到main()并推断出入口类的名字

​代码执行完成之后

spring boot 项目代码,直接启动,第一部分 点睛Spring 4.x 第1 章 Spring 基础 ..........................................2 1.1 Spring 概述 ............................................. 2 1.2 Spring 项目快速搭建 .................................. 5 1.3 Spring 基础配置 .....................................17 第2 章 Spring 常用配置 .... ............................ 30 2.1 Bean 的Scope .... ................................... 30 2.2 Spring EL 和资源调用 .... ...................... 33 2.3 Bean 的初始化和销毁 .... ...................... 37 2.4 Profile .... .... .......... 40 2.5 事件(Application Event) .... .............. 44 第3 章 Spring 高级话题 .... ............................ 48 3.1 Spring Aware .... ..................................... 48 3.2 多线程 .... .... ......... 51 3.3 计划任务 .... .... ..... 54 3.4 条件注解@Conditional .... .................... 56 3.5 组合注解与元注解 .... ........................... 60 3.6 @Enable*注解的工作原理 .... .............. 63 VIII ∣ Java EE 开发的颠覆者:Spring Boot 实战 3.7 测试 .... .... ............. 66 第二部分 点睛Spring MVC 4.x 第4 章 Spring MVC 基础 .... .......................... 72 第三部分 实战Spring Boot 第5 章 Spring Boot 基础 .... ......................... 122 第6 章 Spring Boot 核心 .... ......................... 138 X ∣ Java EE 开发的颠覆者:Spring Boot 实战 第7 章 Spring Boot 的Web 开发 .... ............ 170 7.1 Spring Boot 的Web 开发支持 .... ....... 170 7.2 Thymeleaf 模板引擎 .... ....................... 171 7.2.4 实战 .... ...................................... 177 7.3 Web 相关配置 .... ................................. 182 7.4 Tomcat 配置 .... .................................... 187 7.5 Favicon 配置 .... ................................... 196 7.6 WebSocket .... ....................................... 197 7.7 基于Bootstrap 和AngularJS 的现代Web 应用 .................. 212 第8 章 Spring Boot 的数据访问 .... .............. 233 8.1 引入Docker .... .................................... 237 8.2 Spring Data JPA .... .............................. 248 8.3 Spring Data REST .... ........................... 284 8.4 声名式事务 .... ..................................... 297 8.5 数据缓存Cache .... .............................. 309 8.6 非关系型数据库NoSQL .... ................ 320 8.6.1 MongoDB .... ............................. 320 8.6.2 Redis .... ..................................... 329 第9 章 Spring Boot 企业级开发 .... .............. 340 9.1 安全控制Spring Security .... ............... 340 9.2 批处理Spring Batch .... ....................... 362 9.3 异步消息 .... ......................................... 385 9.4 系统集成Spring Integration .... ........... 395 第10 章 Spring Boot 开发部署与测试 .... ..... 407 第11 章 应用监控 .... ................................... 431 第12 章 分布式系统开发 .... ........................ 456 12.1 微服务、原生云应用 .... ................... 456 12.2 Spring Cloud 快速入门 .... ................. 457 12.3 实战 .... .... ......... 458 12.4 基于Docker 部署 ...................................478
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值