「这是我参与11月更文挑战的第12天,活动详情查看:2021最后一次更文挑战」
SpringBoot在包扫描时,并不会扫描子模块下的内容,这样就使得我们的子模块中的Bean无法注入到Spring容器中。SpringBoot就为我们提供了spring.factories这个文件,让我们可以轻松的将子模块的Bean注入到我们的Spring容器中,本篇文章我们就一起探究一下spring.factories 跨模块实例化Bean的原理。
- 前言
我们在上篇文章中也讲到构建自己构建starter,其中spring.factories就起到重要的作用,我们是通过spring.factories让starer项目中的Bean注入到Web模块的Spring容器中。本篇文章就来探究一下spring.factories文件,更深层次的东西,以及我们是如何借助该文件实例化Bean的。
- 配置
spring.factories文件一般都是配置在src/main/resources/META-INF/ 目录下。
也就是说我们在IDEA新建的SpringBoot项目或者Maven项目的资源文件resources目录下新建一个META-INF文件夹,再建一个spring.factories文件即可,新建的文件没有问题的化,一般IDEA都能自动识别,如下图所示。
spring.factories 的文件内容就是接口对应其实现类,实现类可以有多个
文件内容必须是kv形式,即properties类型
1 | ini复制代码org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.zhj.config.AutoConfiguration |
如其一个接口有多个实现,如下配置
1 | ini复制代码org.springframework.boot.logging.LoggingSystemFactory=\ |
- 原理
在spring -core 中定义了SpringFactoriesLoader 类,这个类就是让spring.factories文件发挥作用的类。SpringFactoriesLoader类的作用就是检索META-INF/spring.factories文件,并获取指定接口将其实现实例化。 在这个类中定义了两个对外的方法:
- loadFactories 根据给定的接口类获取其实现类的实例,这个方法返回的是对象列表
- loadFactoryNames 根据给定的类型加载类路径的全限定类名,这个方法返回的是全限定类名的列表。
源码如下:
1 | typescript复制代码public final class SpringFactoriesLoader { |
- 总结
Spring通过SpringFactoriesLoader实例化Bean的过程
- 获取SpringFactoriesLoader对应的类加载器
- 查找缓存,查看缓存中是否已经读取到所有jar中classpath路径下的META-INF/spring.factories的内容
- 如果缓存已经存在,根据/spring.factories文件中配置的全限定类名通过反射实例化Bean
- 如果缓存中没有值,则扫描所有jar中的这个META-INF/spring.factories文件,并将其以读取到缓存中,并返回这个配置列表
- 然后根据这个全限定类名的列表再通过反射实例化Bean
本文转载自: 掘金