大家好,我是陈谋~SPI(ServiceProviderInterface)是JDK内置的一种服务提供者发现机制,可以用来启用框架扩展和替换组件,主要针对在框架中开发,如Dubbo、Spring、Common-Logging、JDBC等,采用SPI机制,对同一个接口使用不同的实现,提供给不同的用户,从而提高框架的扩展性。之前也写过深入分析JavaSPI:浅谈JavaSPI机制推荐Java工程师技术指南:https://github.com/chenjiabin...JavaSPI通过java.util实现Java内置的SPI.ServiceLoader类解析classPath和jar包META-INF/services/目录下以接口全限定名命名的文件,加载文件中指定的接口实现类完成调用。实例说明创建动态接口publicinterfaceVedioSPI{voidcall();}implementclass1publicclassMp3VedioimplementsVedioSPI{@Overridepublicvoidcall(){System.out.println("thisismp3call");}}实现类2public类Mp4Vedio实现VedioSPI{@Overridepublicvoidcall(){System.out.println("这是mp4调用");}}在项目源码目录下新建META-INF/services/目录,并创建com.skywares。fw.juc.spi.VedioSPI文件。相关测试serviceLoader.forEach(t->{t.call();});}}说明:Java实现spi通过ServiceLoader找到服务提供的工具类。运行结果:源码分析以上只是一个实现java内置SPI功能的简单例子。其实现原理是ServiceLoader是Java内置的查找服务提供接口的工具类。查找服务提供接口是通过调用load()方法实现的,最后遍历一个一个访问服务提供接口的实现类。从源码中可以发现,ServiceLoader类本身实现了Iterable接口,并在其中实现了iterator方法。迭代器方法的实现调用内部类LazyIterator中的方法,迭代器创建一个实例。所有提供服务的接口对应的文件都放在META-INF/services/目录下,最终的类型决定了PREFIX目录不能更改。java提供的SPI机制的思想虽然很好,但是也有相应的缺点。具体如下:Java的内置方法只能通过遍历获取。服务提供者接口必须放在META-INF/services/目录下。针对java的spi存在的问题,Spring的SPI机制沿用了SPI的思想,只是对其进行了扩展和优化。Java工程师推荐技术指南:https://github.com/chenjiabin...SpringSPISpringSPI沿袭了JavaSPI的设计思想,Spring使用spring.factories实现SPI机制,无需实现即可修改Spring源码,提供Spring框架的可扩展性。Spring实例定义接口publicinterfaceDataBaseSPI{voidgetConnection();}相关实现##DB2实现publicclassDB2DataBaseimplementsDataBaseSPI{@OverridepublicvoidgetConnection(){System.out.println("这个数据库是db2");}}##Mysql实现公共类MysqlDataBase实现DataBaseSPI{@OverridepublicvoidgetConnection(){System.out.println("这是mysql数据库");}}1.在项目的META-INF目录下,添加spring.factories文件2.填写相关接口信息,内容如下:com.skywares.fw.juc.springspi.DataBaseSPI=com.skywares。fw.juc.springspi.DB2DataBase,com.skywares.fw.juc.springspi.MysqlDataBase描述了多个实现,用逗号隔开。相关测试类publicclassSpringSPITest{publicstaticvoidmain(String[]args){List
