SPI机制
SPI 全称Service Provider Interface,一种服务发现机制。SPI 的本质是将接口实现类的全限定名配置在文件中,并由服务加载器读取配置文件,加载实现类。可以在运行时,动态为接口替换实现类。可以很容易的通过 SPI 机制为程序提供拓展功能。
Java SPI 实际上是“基于接口的编程+策略模式+配置文件”组合实现的动态加载机制。
Java SPI
当服务的提供者提供一种接口的实现之后,需要在classpath下的META-INF/services/目录里创建一个以服务接口命名的文件,这个文件里的内容就是这个接口的具体的实现类。当其他的程序需要这个服务的时候,就可以通过查找这个jar包(一般都是以jar包做依赖)的META-INF/services/中的配置文件,配置文件中有接口的具体实现类名,可以根据这个类名进行加载实例化,就可以使用该服务。JDK中查找服务实现的工具类是:java.util.ServiceLoader。
定义一个Robot的接口与两个实现类
public interface Robot { void sayHello(); } public class Bumblebee implements Robot { @Override public void sayHello() { System.out.println("Hello, I am Bumblebee."); } } public class OptimusPrime implements Robot { @Override public void sayHello() { System.out.println("Hello, I am Optimus Prime."); } }
META-INF/services 文件夹下创建一个文件,名称为 Robot 的全限定名 org.apache.spi.Robot。文件内容为实现类的全限定的类名,如下:
com.smart.spi.Bumblebee
com.smart.spi.OptimusPrime
测试类
public class SpiTest { @Test public void sayHello() throws Exception { ServiceLoader<Robot> serviceLoader = ServiceLoader.load(Robot.class); System.out.println("Java SPI"); serviceLoader.forEach(Robot::sayHello); } }
应用场景
-
数据库驱动加载接口实现类的加载 JDBC加载不同类型数据库的驱动
-
日志门面接口实现类加载 SLF4J加载不同提供应商的日志实现类
-
Spring Servlet容器启动初始化
org.springframework.web.SpringServletContainerInitializer -
Spring Boot 自动装配过程中,加载META-INF/spring.factories文件,解析properties文件
-
Dubbo Dubbo大量使用SPI技术,里面有很多个组件,每个组件在框架中都是以接口的形成抽象出来,例如Protocol 协议接口
Java SPI源码分析
浙公网安备 33010602011771号