一、JDK SPI机制
什么是SPI
- SPI(全称Service Provider Interface),Java提供的一套用来被第三方实现或者扩展的接口,可以用来启用框架扩展和替换组件。 SPI的作用就是为这些被扩展的API寻找服务实现。
- SPI是服务消费方制定的接口规范(例如JDK制定JDBC规范,各个数据库厂商具体实现,在实际使用中[例如:mybatis框架使用JDK接口进行连接数据库操作])。
- API (Application Programming Interface)是提供方制定接口并完成对接口的实现,消费方仅仅依赖接口调用,且无权选择不同实现 。


public interface UserService {/*** 用户注册接口** @param phone 注册手机号* @return*/String register(String phone);}public class JDUserServiceImpl implements UserService {@Overridepublic String register(String phone) {return "京东用户,注册手机号:"+phone;}}public class ALiUserServiceImpl implements UserService {@Overridepublic String register(String phone) {return "阿里巴巴注册用户,注册手机号:"+phone;}public class SPIDemo {public static void main(String[] args) {ServiceLoader<UserService> serviceLoaders = ServiceLoader.load(UserService.class);serviceLoaders.forEach(server -> {//System.out.println("调用服务");System.out.println(server.register("110"));});}}输出:阿里巴巴注册用户,注册手机号:110京东用户,注册手机号:110
SPI应用
mybatis、shardingSphere框架都用到了JDK的SPI技术。mybatis在连接不同数据库实现中,读取驱动包下META-INF/services/java.sql.Driver文件(java.sql.Driver为接口名)中配置的连接数据库的实现(Driver实现类)
Java中SPI局限
只能遍历所有的实现,并全部实例化。
配置文件中只是简单的列出了所有的扩展实现,无法对扩展实现命名。导致在程序中很难去准确的引用它们。
扩展如果依赖其他的扩展,做不到自动注入和装配。
扩展很难和其他的框架集成,比如扩展里面依赖了一个Spring bean,原生的Java SPI不支持。
二、SPI优势
不需要改动源码就可以实现扩展,解耦。
实现扩展对原来的代码几乎没有侵入性。
只需要添加配置就可以实现扩展,符合开闭原则。
