前言
依赖自动发现机制是为了提高程序的扩展性,降低代码的耦合度。在不对核心代码做修改和配置的前提下,只需在classpath下添加依赖,就能将插件接入到系统中。
遵循的基本原则
面向接口编程
核心代码面向接口编程
约定大于配置
根据约定目录下的配置,读取并加载接口实现类
JDK自带的SPI
SPI 全称为 (Service Provider Interface) ,是JDK内置的一种服务提供发现机制(动态替换接口实现)
java spi的具体约定为:当服务的提供者,提供了服务接口的一种实现之后,在jar包的META-INF/services/目录里同时创建一个以服务接口命名的文件。该文件里就是实现该服务接口的具体实现类。而当外部程序装配这个模块的时候,就能通过该jar包META-INF/services/里的配置文件找到具体的实现类名,并装载实例化,完成模块的注入。 基于这样一个约定就能很好的找到服务接口的实现类,而不需要再代码里制定。jdk提供服务实现查找的一个工具类:java.util.ServiceLoader
通常用来为框架提供扩展性、兼容性和第三方插件接口:最常见的就是JDBC驱动,不同的数据厂家对应不同的驱动
例如, 有个接口,想运行时动态的给它添加实现,你只需要添加一个实现的依赖包到classpath,在这个依赖包工程中,通过一个文件声明实现类与SPI的对应关系
在classpath下的MATE-INF/services目录下创建一个文件,文件名为JDK的SPI全路径名,文件内容为当前依赖包中的该SPI的实现类(可以有多个,用逗号隔开)。文件编码必须是UTF-8
当JVM启动时,会扫描classpath MATE-INF/services目录下所有的文件,得到SPI与实现类的映射关系
通过ServiceLoader来加载SPI对应的实现类
ServiceLoader loaders = ServiceLoader.load(HelloInterface);
for (HelloInterface hello : loaders) {
hello.sayHello();
}
Dubbo实现的SPI
Dubbo的扩展机制是基于SPI思想来实现的,但是并没有采用JDK中原生的SPI机制,因为JDK中SPI具有很大的缺点:
JDK中标准的SPI会一次性实例化扩展点所有的实现类,不管这些实例化出来的扩展点实现有没有被用到。有的扩展点实现初始化时非常的耗时,即使没有用到也会被加载,这样就很浪费资源
Dubbo中的SPI概述
Dubbo的SPI机制中增加了对扩展