掘金 后端 ( ) • 2024-04-12 23:04

highlight: atelier-cave-dark
theme: channing-cyan

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

createSpringFactoriesInstances

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

// 参数分别是 类型,参数类型,类加载器,参数,类名称
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;
}

image.png

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

run

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

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

private DefaultBootstrapContext createBootstrapContext() {
// 通过无参构造实例化了一个对象
   DefaultBootstrapContext bootstrapContext = new DefaultBootstrapContext();
   // 遍历SpringApplication的构造方法中读取spring.factories配置文件中BootStrapRegistryInitializer并实例化的对象,并调用它们的initialize方法,这是一个扩展点哟。如果我们给spring.factories中添加BootStrapRegistryInitializer的配置在这里也会执行
   this.bootstrapRegistryInitializers.forEach((initializer) -> initializer.initialize(bootstrapContext));
   return bootstrapContext;
}

image.png