带你了解SpringBoot项目的SpringApplication初始化

SpringBoot项目的mian函数

@SpringBootApplication
public class SpringBootMyTestApplication {
   public static void main(String[] args) {
      SpringApplication.run(SpringBootMyTestApplication.class, args);
   }
}

进入run主方法中,

public static ConfigurableApplicationContext run(Class<?>[] primarySources, String[] args) {
   // 两件事:1.初始化SpringApplication 2.执行run方法
   return new SpringApplication(primarySources).run(args);
}

好了,带你进入正题。
SpringApplication 实例化过程,首先是进入带参数的构造方法,最终回来到两个参数的构造方法:

public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
   this.resourceLoader = resourceLoader;
   Assert.notNull(primarySources, "PrimarySources must not be null");
   //将primarySources数组转换为List,最后放到LinkedHashSet集合中
   this.primarySources = new LinkedHashSet<>(Arrays.asList(primarySources));
   //【1.1 推断应用类型,后面会根据类型初始化对应的环境。常用的一般都是servlet环境 】
   this.webApplicationType = WebApplicationType.deduceFromClasspath();
   //【1.2 初始化classpath下 META-INF/spring.factories中已配置的ApplicationContextInitializer 】
   setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
   //【1.3 初始化classpath下所有已配置的 ApplicationListener 】
   setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
   //【1.4 根据调用栈,推断出 main 方法的类名 】
   this.mainApplicationClass = deduceMainApplicationClass();
}

1. 推断应用类型

点击进入WebApplicationType.deduceFromClassPath()方法:

static WebApplicationType deduceFromClasspath() {
   //classpath下必须存在org.springframework.web.reactive.DispatcherHandler
   if (ClassUtils.isPresent(WEBFLUX_INDICATOR_CLASS, null) && !ClassUtils.isPresent(WEBMVC_INDICATOR_CLASS, null)
         && !ClassUtils.isPresent(JERSEY_INDICATOR_CLASS, null)) {
      return WebApplicationType.REACTIVE;
   }
   for (String className : SERVLET_INDICATOR_CLASSES) {
      if (!ClassUtils.isPresent(className, null)) {
         return WebApplicationType.NONE;
      }
   }
   //classpath环境下存在javax.servlet.Servlet或者org.springframework.web.context.ConfigurableWebApplicationContext
   return WebApplicationType.SERVLET;
}

因为项目中引入了Web的依赖,所以是一个Web项目,这个地方最终返回的是SERVLET,这个也是最常用的类型。

2. 初始化ApplicationContextInitializer

在这里插入图片描述

从图中可以看出,最终初始化了7个ApplicationContextInitializer,而且这个7个对象是从classpath下 META-INF/spring.factories中获取,验证一下,进入getSpringFactoriesInstances方法:
在这里插入图片描述
在这里插入图片描述查询配置:
在这里插入图片描述
在这里插入图片描述这样也就找到了初始化是获取的7个ApplicationContextInitializer的配置。ApplicationContextInitializer 是Spring框架的类, 这个类的主要目的就是在ConfigurableApplicationContext 调用refresh()方法之前,回调这个类的initialize方法。通过 ConfigurableApplicationContext 的实例获取容器的环境Environment,从而实现对配置文件的修改完善等工作。

3. 初始化ApplicationListener

和上面ApplicationContextInitializer的初始化同理,也是在classpath下META-INF/spring.factories中获取,验证一下:
在这里插入图片描述
一共是11个,从META-INF/spring.factories中找一下:
在这里插入图片描述
在这里插入图片描述刚好11个,这也验证了ApplicationListener的初始化过程。

4. 推断main方法所在的启动类

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;
}

在这里插入图片描述从图中可以看出,这个也就是我们通常定义的启动类。

Spring Boot项目中,可以使用初始化代码来实现项目启动时的一些初始化操作。下面以示例代码进行解释: 1. 创建一个类,命名为ApplicationRunnerImpl实现ApplicationRunner接口,该接口继承了CommandLineRunner接口,用于在Spring Boot项目启动之后执行特定的代码。 ```java import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @Component public class ApplicationRunnerImpl implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { // 这里写入初始化代码,例如加载配置、数据库连接等操作 System.out.println("Spring Boot项目启动初始化代码执行!"); } } ``` 2. 在启动类中,使用@SpringBootApplication注解启动Spring Boot应用程序。 ```java import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } } ``` 在上述示例代码中,当Spring Boot项目启动之后,ApplicationRunnerImpl类中的run方法会被执行,可以在此方法中编写一些初始化的代码。比如加载配置文件、初始化数据库连接等。上面的例子中,run方法内只打印了一条信息。实际应用中,可以根据需要编写具体的初始化逻辑。 当代码执行时,控制台会打印出"Spring Boot项目启动初始化代码执行!"的信息,表示初始化代码成功执行。 这种方式非常适用于需要在项目启动时执行一些初始化操作的场景,可以方便地集成到Spring Boot框架中,实现项目的自动初始化
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值