主要目的
SPI的本质是java的一种服务发现能力。
如果同时面临下面两个问题,就可以使用SPI
**0)AB模块使用不同的类加载器,且A模块的加载器无法加载B模块
1)A模块依赖B模块。
2)A模块又要先于B模块被类加载,或者不能确定两个模块的类加载顺序。
大部分场景其实根本不需要SPI。合理的类依赖可以避免这个问题。
SPI的本质思路很简单,就是使用线程上下文加载器去加载用到的类。SPI不是JVM提供的能力,而是JDK中提供的tricky但必要的能力。
一个简单的demo
具体的例子见
https://blog.csdn.net/qq_27292113/article/details/100324127
核心代码如下
- 在核心jar中定义接口,并使用接口代码
- 在外部jar中定义services
- 使用是是会选择第一个实现
通过ServiceLoader完成加载
类加载机制
实际应用
JAVA日志
启动时,我们可以看见,slf4j找到了多个SPI的实现。
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/gdl/.m2/repository/org/slf4j/slf4j-log4j12/1.6.1/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/gdl/.m2/repository/org/apache/logging/log4j/log4j-slf4j-impl/2.10.0/log4j-slf4j-impl-2.10.0.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.Log4jLoggerFactory]
SpringBoot
JDBC
java.sql.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;
注释上写的很清楚
DriverManager类会被Bootstrap类加载器加载。但是这个时候,他是在核心库中找不到具体实现模块的。所以,他必须先去寻找自己需要加载的模块,再完成本类的加载。
driver接口定义了如下方法
可以看到有诸多的实现。
简单而言,就是自动加载:DriverManager的静态代码块执行的时刻,使用该时刻当前线程类加载器加载java.sql.Driver文件,并用当前线程类加载器加载及、实例化、registerDriver