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;
}
相关推荐
小李不想输啦2 小时前
什么是微服务、微服务如何实现Eureka,网关是什么,nacos是什么
java·spring boot·微服务·eureka·架构
HaiFan.6 小时前
SpringBoot 事务
java·数据库·spring boot·sql·mysql
2401_882727576 小时前
低代码配置式组态软件-BY组态
前端·后端·物联网·低代码·前端框架
追逐时光者7 小时前
.NET 在 Visual Studio 中的高效编程技巧集
后端·.net·visual studio
大梦百万秋8 小时前
Spring Boot实战:构建一个简单的RESTful API
spring boot·后端·restful
斌斌_____8 小时前
Spring Boot 配置文件的加载顺序
java·spring boot·后端
路在脚下@8 小时前
Spring如何处理循环依赖
java·后端·spring
苹果醋39 小时前
React系列(八)——React进阶知识点拓展
运维·vue.js·spring boot·nginx·课程设计
海绵波波1079 小时前
flask后端开发(1):第一个Flask项目
后端·python·flask
小奏技术10 小时前
RocketMQ结合源码告诉你消息量大为啥不需要手动压缩消息
后端·消息队列