spi机制

spi(Service Provider Interface)
用于接口编程,主要应用于调用其他厂商实现并部署在classpath下的jar包,如jndi,jdbc等
在jdk6后,提供了java.util.ServiceLoader类,采用META-INF/services/中的配置信息
在这里插入图片描述
对于ServiceLoader类,采用了懒加载,在其内部,可以看到
private LazyIterator lookupIterator;
的成员变量代码,在使用Service.load方法后,并不会真正加载实现类,而是返回一个Service服务类,在真正使用到的时候,即调用迭代器next()方法后,才加载服务实现类

以jdbc进行测试,引入mysql的maven依赖后,主类如下

public class SPI_JDBCTest {
    public static void main(String[] args) throws Exception {
    
        ServiceLoader<Driver> load = ServiceLoader.load(Driver.class);
        Iterator<Driver> iterator = load.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next().getClass());
        }
    }
}

SPI_JDBCTest为启动类,会先加载,其又依赖到了Driver类和ServiceLoader类,会尝试加载
添加虚拟机参数 -XX:+TraceClassLoading后,查看类加载顺序,
SPI_JDBCTest > java.lang.Driver > java.util.ServiceLoader > com.mysql.cj.jdbc.Driver
在这里插入图片描述
调用ServiceLoader.load(Driver.class)方法,并不会直接加载com.mysql.cj.jdbc.Driver类,而是创建了一个ServiceLoader对象并返回

在这里插入图片描述
ServiceLoader构造函数:
在这里插入图片描述
reload方法,先清空服务缓冲区,即成员变量
private LinkedHashMap<String,S> providers = new LinkedHashMap<>();
再创建懒加载迭代器
在这里插入图片描述
通过debug,可以看到,调用iterator.hasNext()后,会进入到ServiceLoader内部类LazyIterator中的hasNextService()方法
在这里插入图片描述
在这里插入图片描述
应用类加载器会搜索classpath下jar 中META-INF/services/目录
查找java.sql.Driver文件,将要加载的驱动名称保存下来
在这里插入图片描述
在这里插入图片描述

在调用iterator.next()后,进入nextService()方法,可以看到,使用之前保存的全限定名加载驱动类
在这里插入图片描述
继续debug,可以看到进入了com.mysql.cj.jdbc.Driver类的静态代码块中,即进行类的初始化,之后程序结束

对于jdbc4.0以前,加载驱动需要显式指定,使用代码

Class.forName("com.mysql.cj.jdbc.Driver");

可以使用系统类加载器将com.mysql.cj.jdbc.Driver类加载进内存

以后,使用jdbc不用再显式使用此代码,直接获取连接即可使用,底层会使用ServiceLoader
在DriverManager的静态代码块中,loadInitialDrivers()方法会通过ServiceLoader类加载驱动
在这里插入图片描述
driversIterator.next()方法会进入到ServiceLoader内部类LazyIterator中的hasNextService()方法,加载驱动
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值