Spring Boot源码分析三:启动流程

本文是作者写关于Spring源码的第一篇文章,作者水平有限,所有的源码文章仅限用作个人学习记录。文中如有错误欢迎各位留言指正。

createSpringFactoriesInstances

上文说到读取配置文件spring.factories时,将读取到配置文件中的类进行实例化,现在来看这个方法。

java 复制代码
// 参数分别是 类型,参数类型,类加载器,参数,类名称
private <T> List<T> createSpringFactoriesInstances(Class<T> type, Class<?>[] parameterTypes,
      ClassLoader classLoader, Object[] args, Set<String> names) {
      // 初始化一个与类名集合大小一样的集合
   List<T> instances = new ArrayList<>(names.size());
   // 遍历类名集合逐一实例化
   for (String name : names) {
      try {
         // 这里又实用到了ClassUtils,使用这个工具类获取到这个类名称字符串的类型。这个工具类的forName方法的写法很好,我在很多方法都有看到类似的影子。
         // 逻辑大概就是先判断是不是基础类型,如果不是就用类加载器进行加载
         // 只要是我们自己定义的类就是这样Class.forName(name, false, clToUse);
         Class<?> instanceClass = ClassUtils.forName(name, classLoader);
         // 判断type这个Class是不是instanceClass的超类
         Assert.isAssignable(type, instanceClass);
         // 找到Class的指定参数类型的构造方法
         Constructor<?> constructor = instanceClass.getDeclaredConstructor(parameterTypes);
         // 通过构造方法和参数实例化一个类的对象。这又有一个工具类了
         T instance = (T) BeanUtils.instantiateClass(constructor, args);
         // 保存实力对象
         instances.add(instance);
      }
      catch (Throwable ex) {
         throw new IllegalArgumentException("Cannot instantiate " + type + " : " + name, ex);
      }
   }
   return instances;
}

实例化SpringApplication的构造方法分析完了,接下来就看看SpringApplication的成员方法run方法的逻辑。

run

这个方法有点多,不同版本也有一定的差异。

java 复制代码
public ConfigurableApplicationContext run(String... args) {
// 为了计时用的,老版本和新版本不一样
   long startTime = System.nanoTime();
   // 初始化一个引导器的上下文,这是属于Spring Boot的上下文。后边还有一个Spring的上下文。apach好喜欢context这个东西,证明写框架这个context是真的好用。
   DefaultBootstrapContext bootstrapContext = createBootstrapContext();
   ConfigurableApplicationContext context = null;
   configureHeadlessProperty();
   SpringApplicationRunListeners listeners = getRunListeners(args);
   listeners.starting(bootstrapContext, this.mainApplicationClass);
   try {
      ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
      ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
      configureIgnoreBeanInfo(environment);
      Banner printedBanner = printBanner(environment);
      context = createApplicationContext();
      context.setApplicationStartup(this.applicationStartup);
      prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
      refreshContext(context);
      afterRefresh(context, applicationArguments);
      Duration timeTakenToStartup = Duration.ofNanos(System.nanoTime() - startTime);
      if (this.logStartupInfo) {
         new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), timeTakenToStartup);
      }
      listeners.started(context, timeTakenToStartup);
      callRunners(context, applicationArguments);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, listeners);
      throw new IllegalStateException(ex);
   }
   try {
      Duration timeTakenToReady = Duration.ofNanos(System.nanoTime() - startTime);
      listeners.ready(context, timeTakenToReady);
   }
   catch (Throwable ex) {
      handleRunFailure(context, ex, null);
      throw new IllegalStateException(ex);
   }
   return context;
}

createBootstrapContext

java 复制代码
private DefaultBootstrapContext createBootstrapContext() {
// 通过无参构造实例化了一个对象
   DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
   // 遍历SpringApplication的构造方法中读取spring.factories配置文件中BootStrapRegistryInitializer并实例化的对象,并调用它们的initialize方法,这是一个扩展点哟。如果我们给spring.factories中添加BootStrapRegistryInitializer的配置在这里也会执行
   this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
   return bootstrapContext;
}
相关推荐
AI多Agent协作实战派18 小时前
AI多Agent协作系统实战(四十八):改个名,整个AI团队都不认识人了
后端
wei_shuo18 小时前
KES 故障诊断与应急响应:问题排查、根因分析与应急预案
后端
LinMINGJing00718 小时前
postgre分区方式
后端
王中阳Go18 小时前
业务代码凭什么不能直接调 Agent?——我在律所 AI 项目里做的 Harness 运行时治理
人工智能·后端·程序员
宠友信息19 小时前
IM系统开发技术路线分析,即时通讯源码助力快速搭建聊天应用
java·spring boot·redis·websocket·mysql·uni-app·vue
SomeB1oody19 小时前
【RustyML入门】7.2. 深入模型持久化
开发语言·后端·机器学习·rust·教程
知几蜗牛19 小时前
0 后端 · 0 数据库 · 0 备案:用 AI 两天搓出的股票管理系统,开源了
前端·后端·llm
风流 少年20 小时前
Spring AI 2.0:阿里云百炼平台(工作流应用)
java·后端·spring
__zRainy__20 小时前
Node系列 · 数据库:单表查询
数据库·后端·mysql·node.js
诺伦20 小时前
Rust 错误处理实战:从 unwrap 到优雅 Result 的进阶之路
开发语言·后端·rust