所以也可以看出,Spring的SPI机制跟Java的不论是文件名还是内容约定都不一样 。
来个demo在META-INF/目录下创建spring.factories文件,LoadBalance为键,RandomLoadBalance为值

文章插图
测试:
public class SpringFactoriesLoaderDemo {public static void main(String[] args) {List<LoadBalance> loadBalances = SpringFactoriesLoader.loadFactories(LoadBalance.class, MyEnableAutoConfiguration.class.getClassLoader());for (LoadBalance loadBalance : loadBalances) {System.out.println("获取到LoadBalance对象:" + loadBalance);}}}运行结果:
文章插图
成功获取到了实现对象 。
核心原理如下是SpringFactoriesLoader中一段核心代码

文章插图
其实从这可以看出,跟Java实现的差不多,只不过读的是META-INF/目录下spring.factories文件内容,然后解析出来键值对 。
使用场景Spring的SPI机制在内部使用的非常多,尤其在SpringBoot中大量使用,SpringBoot启动过程中很多扩展点都是通过SPI机制来实现的,这里我举两个例子
1、自动装配在SpringBoot3.0之前的版本,自动装配是通过SpringFactoriesLoader来加载的 。

文章插图
但是SpringBoot3.0之后不再使用SpringFactoriesLoader,而是Spring重新从META-INF/spring/目录下的org.springframework.boot.autoconfigure.AutoConfiguration.imports文件中读取了 。

文章插图
至于如何读取的,其实猜也能猜到就跟上面SPI机制读取的方式大概差不多,就是文件路径和名称不一样 。
2、PropertySourceLoader的加载PropertySourceLoader是用来解析Application配置文件的,它是一个接口
SpringBoot默认提供了 PropertiesPropertySourceLoader 和 YamlPropertySourceLoader两个实现,就是对应properties和yaml文件格式的解析 。
SpringBoot在加载PropertySourceLoader时就用了SPI机制

文章插图
与Java SPI机制对比首先Spring的SPI机制对Java的SPI机制对进行了一些简化,Java的SPI每个接口都需要对应的文件,而Spring的SPI机制只需要一个spring.factories文件 。
其次是内容,Java的SPI机制文件内容必须为接口的实现类,而Spring的SPI并不要求键值对必须有什么关系,更加灵活 。
第三点就是Spring的SPI机制提供了获取类限定名的方法loadFactoryNames,而Java的SPI机制是没有的 。通过这个方法获取到类限定名之后就可以将这些类注入到Spring容器中,用Spring容器加载这些Bean,而不仅仅是通过反射 。
但是Spring的SPI也同样没有实现获取指定某个指定实现类的功能,所以要想能够找到具体的某个实现类,还得依靠具体接口的设计 。
所以不知道你有没有发现,PropertySourceLoader它其实就是一个策略接口,注释也有说,所以当你的配置文件是properties格式的时候,他可以找到解析properties格式的PropertiesPropertySourceLoader对象来解析配置文件 。
Dubbo SPI机制--ExtensionLoaderExtensionLoader是dubbo的SPI机制的实现类 。每一个接口都会有一个自己的ExtensionLoader实例对象,这点跟Java的SPI机制是一样的 。
同样地,Dubbo的SPI机制也做了以下几点约定:
- 接口必须要加@SPI注解
- 配置文件可以放在META-INF/services/、META-INF/dubbo/internal/ 、META-INF/dubbo/ 、META-INF/dubbo/external/这四个目录底下,文件名也是接口的全限定名
- 内容为键值对,键为短名称(可以理解为spring中Bean的名称),值为实现类的全限定名
@SPIpublic interface LoadBalance {}然后,修改一下Java的SPI机制测试时配置文件内容,改为键值对,因为Dubbo的SPI机制也可以从META-INF/services/目录下读取文件,所以这里就没重写文件random=com.sanyou.spi.demo.RandomLoadBalance测试类:public class ExtensionLoaderDemo {public static void main(String[] args) {ExtensionLoader<LoadBalance> extensionLoader = ExtensionLoader.getExtensionLoader(LoadBalance.class);LoadBalance loadBalance = extensionLoader.getExtension("random");System.out.println("获取到random键对应的实现类对象:" + loadBalance);}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 静态路由or动态路由,一个例子说明白!
- 贾玲|真被热巴说中了!曝贾玲秘密生子,范丞丞冲上热搜榜一
- 阿里p6是什么级别(p6级别工资标准)
- 闭口是什么意思(如何去闭口)
- 厂长为什么叫7酱(lpl解说鼓鼓多人运动)
- 裁剪视频用什么软件(电商视频剪辑用什么软件)
- 拜灶神要说什么 拜灶神要怎样说话
- 西装裤配什么鞋子(西装裤怎么搭配上衣)
- 谛听为什么不说出真相(谛听为啥听出来真假不说)
- 每个手指戴戒指的含义怎么说 每个手指戴戒指的含义
