主要目的
如果同时面临下面两个问题,就可以使用SPI
1)A模块依赖B模块。
2)A模块又要先于B模块被类加载。
大部分场景其实根本不需要SPI。合理的类依赖可以避免这个问题。
一个简单的demo
具体的例子见
https://blog.csdn.net/qq_27292113/article/details/100324127
核心代码如下
- 在外部jar中定义services
- 使用是是会选择第一个实现
类加载机制
实际应用
JDBC
DriverManager类会在其static代码段执行
ServiceLoader<Driver> loadedDrivers = ServiceLoader.load(Driver.class);
Iterator<Driver> driversIterator = loadedDrivers.iterator();
/* Load these drivers, so that they can be instantiated.
* It may be the case that the driver class may not be there
* i.e. there may be a packaged driver with the service class
* as implementation of java.sql.Driver but the actual class
* may be missing. In that case a java.util.ServiceConfigurationError
* will be thrown at runtime by the VM trying to locate
* and load the service.
*
* Adding a try catch block to catch those runtime errors
* if driver not available in classpath but it's
* packaged as service and that service is there in classpath.
*/
try{
while(driversIterator.hasNext()) {
driversIterator.next();
}
} catch(Throwable t) {
// Do nothing
}
return null;
注释上写的很清楚
driver接口定义了如下方法
可以看到有诸多的实现。
简单而言,就是自动加载:DriverManager的静态代码块执行的时刻,使用该时刻当前线程类加载器加载java.sql.Driver文件,并用当前线程类加载器加载及、实例化、registerDriver