SPI和类加载器

本文介绍了Java SPI的本质,即一种服务发现能力。当面临模块类加载问题时可使用SPI,其本质思路是用线程上下文加载器加载类。还给出简单demo,通过ServiceLoader完成加载,并阐述了类加载机制,最后介绍了SPI在JAVA日志、SpringBoot、JDBC中的实际应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

主要目的

SPI的本质是java的一种服务发现能力。
如果同时面临下面两个问题,就可以使用SPI
**0)AB模块使用不同的类加载器,且A模块的加载器无法加载B模块
1)A模块依赖B模块。
2)A模块又要先于B模块被类加载,或者不能确定两个模块的类加载顺序。

大部分场景其实根本不需要SPI。合理的类依赖可以避免这个问题。
SPI的本质思路很简单,就是使用线程上下文加载器去加载用到的类。SPI不是JVM提供的能力,而是JDK中提供的tricky但必要的能力。

一个简单的demo

具体的例子见
https://blog.youkuaiyun.com/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

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值