SpringBoot探索02 – 启动过程之getSpringFactoriesInstances

最近计划整理下SpringBoot的启动过程以及API请求返回过程,以便支持后续的部分内容,也方便实现一周一文的计划。

先做SpringBoot启动流程分析。

初见

在SpringBoot启动代码的开头部分可以看到如下的内容:

比较显眼的是getSpringFactoriesInstances方法——这个方法出现了两次,而且以后还会继续出现。

从代码上看来,这个方法的作用应该就是获取指定类型的实例集合。

具体如何,还得继续走走看。从这里一步步走下去,可以看到一个重载的方法,这个方法的内容比较实在:

关键是方法体中的三四两行。第三行应该是获取了名称集合,第四行则应是获取了名称对应的实例集合。

问名

首先看看SpringFactoriesLoader.loadFactoryNames方法做了哪些事情。这个方法的核心内容在于它调用的loadSpringFactories方法。loadSpringFactories的方法体稍稍长了一些,沾出来显得太啰嗦,所以仅在下面介绍下这个方法具体做了那些事情。

这个类的作用是根据类加载器获取类名称集合(map结构,接口->实现类集合),具体流程如下:

  1. 首先尝试从内存缓存中获取,如获取到就立即返回,没有则继续下面内容;
  2. 从类加载路径(的jar文件)中获取全部的spring.factories文件路径;
  3. 循环遍历读取这些文件中的键值对(K->List[V]);
  4. 将读取内容放入内存缓存,下次再调用这个方法时会优先从缓存中获取;
  5. 返回读取到的全部键值对集合(Map[K,List[V]]结构)。

简单做些解释:

spring.factories文件本质上是一个.properties文件,也就是说,它的内容是键值对集合,下面是一段示例:

这个片段中有三个键值对。根据后面的代码可知spring.factories文件中每个键值对的key是一个接口的名称,value则是实现类名称的集合(以“,”分隔)。

spring.factories文件中的内容会被读取到一个(K->List[V])结构的Map中。最终全部这些内容又会以类加载器实例为key保存在内存缓存中。

然后,SpringFactoriesLoader.loadFactoryNames方法就可以根据接口的名称获取到接口的实现类的名称集合了。

得意

在得到类名称集合后就是根据类名构建类对应的实例了。这是createSpringFactoriesInstances方法做的事情。这个方法不长,可以粘出来看看:

方法的内容很清晰也很简单:

  1. 根据方法名获取Class实例;
  2. 通过Class实例获取构造器;
  3. 使用构造器构建类实例。

很普通的一个反射过程。期间有一个校验是判断Class是不是指定接口的子类;还有就是在BeanUtils.instantiateClass中创建实例的时候修改了构造器的可见性范围,并提供了对Kotlin的支持。

这块儿内容大体上就这样了。至于这里获取到了哪些ApplicationContextInitializerApplicationListener的实例,以及它们的作用,在后续的部分会陆续提到。

End!

发表评论

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据