简介
SPI(Service Provider Interface),是JDK内置的一种服务提供发现机制,主要核心就是解耦,一般用于框架的模块化开发,或者可拔插组件开发。
业内案例
logback
实现类
ch.qos.logback.classic.servlet.LogbackServletContainerInitializer
log4j
实现类
org.apache.logging.log4j.util.EnvironmentPropertySource
org.apache.logging.log4j.util.SystemPropertiesPropertySource
spring-web
实现类org.springframework.web.SpringServletContainerInitializer
JDBC
通常各大数据库厂商(如Mysql、Oracle)会根据一个统一的规范:java.sql.Driver
开发各自的驱动实现逻辑。客户端使用jdbc时不需要去改变代码,直接引入不同的spi接口服务即可。
JDBC4之前,需要先加载驱动,例如:Class.forName("com.mysql.jdbc.Driver");
JDBC4之后,则不需要再显式通过Class.forName加载驱动,由于DriverManager在静态块通过SPI完成了注册过程,代码如下
static {
loadInitialDrivers();
println("JDBC DriverManager initialized");
}
private static void loadInitialDrivers() {
……
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
while(driversIterator.hasNext()) {
driversIterator.next();
}
……
}
……
}
}
在DriverManager.getConnection(String url,String user,String pass)方法中已经有了spi的实现,会默认去加载驱动类。
此外,Dubbo中也大量用到spi机制。
本地实现
如图
优缺点
优点:面向接口的编程,解耦,可拔插,适合于各种组件式开发,商业性开发。
缺点:需要遍历所有的实现,并实例化,资源浪费,获取某个实现类的方式不够灵活,多线程使用 ServiceLoader 类的实例不安全。