1.SPI介绍在基于接口编程时,两个模块需要接口进行交互。如果接口在被调用者中,则属于API。如果接口在调用者中,则属于SPIAPI,ApplicationProgrammingInterface,应用程序编程接口SPI,ServiceProviderInterface,服务提供者接口,是一种服务发现机制。JDK的java.util包中有一个ServiceLoader类,可以通过配置文件加载指定的服务提供者。被调用者提供服务接口及其实现后,只需要在META-INF/services/目录下创建一个以接口全名命名的文件,然后列出该接口的具体实现类全名在文件中,调用者可以使用ServiceLoader来加载这些实现类。从而实现功能2.SPI的例子光看介绍有点乱。下面用一个简单的例子来演示SPI的使用。首先声明一个接口:com.example.summerboot.spi.Animal,其中声明方法sound:packagecom.example.summerboot.spi;publicinterfaceAnimal{voidsound();}然后实现两个Animal接口类及其方法:}}publicclassDogimplementsAnimal{@Overridepublicvoidsound(){System.out.println("wang!wang!");}}然后,在META-INF/services中创建一个文件,命名为com.example.summerboot.spi.Animal,这是接口的全名,列出两个实现类的全名。最后使用ServiceLoader的load方法加载两个实现类并调用它们的sound方法:publicclassSpiTest{publicstaticvoidmain(String[]args){ServiceLoaderload=ServiceLoader.load(Animal.class);for(Animalanimal:load){animal.sound();}}}运行结果:值得注意的是,ServiceLoader可以加载所有jar包中META-INF/services下接口的实现类。例如,如果我们将上述代码修改为:publicclassSpiTest{publicstaticvoidmain(String[]args){ServiceLoaderload=ServiceLoader.load(Animal.class);for(Animalanimal:load){animal.sound();}ServiceLoaderdrivers=ServiceLoader.load(Driver.class);for(Driverdriver:drivers){System.out.println(driver.getClass().getName());}}}运行结果:可以看到在加载Driver接口的时候,mysql和druid中的Driver实现类也被加载进来了。分别打开mysql和druid的jar包,可以看到java.sql.Driver文件在其配置的META-INF/services下3.SPI在DriverManager中的应用在使用JDBC连接数据库之前,需要使用DriverManager获取连接,那么它是如何判断应该加载哪个驱动的呢?答案是加载,然后遍历调用所有驱动的connect方法,然后每个驱动判断url是否是自己支持的类似这样的代码:if(!ConnectionUrl.acceptsUrl(url)){/**空调根据JDBC规范:*如果驱动程序意识到连接到给定URL的驱动程序类型错误,则它应该返回“null”。这很常见,因为当*JDBC驱动程序管理器被要求连接到给定的URL时,它会依次将URL传递给每个加载的驱动程序。*/returnnull;}那么DriverManager是如何加载驱动的呢?以mysql为例:首先,DriverManager中有一段静态代码段,用来加载和初始化驱动程序static{loadInitialDrivers();println("JDBCDriverManagerinitialized");}在loadInitialDrivers方法中,你会看到这样的代码可以看出DriverManager也是使用了SPI,使用ServiceLoader来加载所有写在配置文件中的Driver。for(StringaDriver:driversList){try{println("DriverManager.Initialize:loading"+aDriver);Class.forName(aDriver,true,ClassLoader.getSystemClassLoader());}catch(Exceptionex){println("DriverManager.Initialize:loadfailed:"+ex);}}参考JavaSPI思想:https://zhuanlan.zhihu.com/p/...