SPI机制入门、SPI机制原理

https://blog.csdn.net/qq_20397315/article/details/106095184

SPI ,全称为 Service Provider Interface,是一种服务发现机制。它通过在ClassPath路径下的META-INF/services文件夹查找文件,自动加载文件里所定义的类。


使用入门

创建接口和其实现类

public interface DbInterface {
    void say();
}
public class Db1 implements DbInterface {
    @Override
    public void say() {
        System.out.println("DB1");
    }
}
public class Db2 implements DbInterface {
    @Override
    public void say() {
        System.out.println("DB2");
    }
}

resource目录下创建META-INF/services目录,并在改目录下创建一个名为接口全限定名的文件

我这里是com.zy.spi.DbInterface
在这里插入图片描述

com.zy.spi.DbInterface文件中填写接口实现类的全限定名;

com.zy.spi.Db1
com.zy.spi.Db2

使用

    @Test
    public void t1() {
    //java.util.ServiceLoader
        ServiceLoader<DbInterface> load = ServiceLoader.load(DbInterface.class);
        load.forEach(DbInterface::say);
        /*for (DbInterface dbInterface : load) {
            dbInterface.say();
        }*/
    }

可以看到,java.util.ServiceLoader类位于java.util包下,却加载到了我们自己定义的Db1和DB21类


SPI机制原理

https://blog.csdn.net/qq_20397315/article/details/106095184

ServiceLoader.load方法

    public static <S> ServiceLoader<S> load(Class<S> service) {
        ClassLoader cl = Thread.currentThread().getContextClassLoader();
        return ServiceLoader.load(service, cl);
    }

可以看到使用的是线程上下文类加载器来打破双亲委派模型;

线程上下文类加载器详解

ServiceLoader实现了Iterable,只有在我们迭代ServiceLoader对象时,才会去加载META-INF/services目录下文件中的记录的类(懒加载);

最终调用的方法是hasNextService()

        private boolean hasNextService() {
            if (nextName != null) {
                return true;
            }
            if (configs == null) {
                try {
        //PREFIX : private static final String PREFIX = "META-INF/services/";
        //service.getName() 即接口的全限定名
                    String fullName = PREFIX + service.getName();
                    if (loader == null)
                        configs = ClassLoader.getSystemResources(fullName);
                    else
                        configs = loader.getResources(fullName);
                } catch (IOException x) {
                    fail(service, "Error locating configuration files", x);
                }
            }
            while ((pending == null) || !pending.hasNext()) {
                if (!configs.hasMoreElements()) {
                    return false;
                }
                pending = parse(service, configs.nextElement());
            }
            nextName = pending.next();
            return true;
        }

MySQL驱动使用了SPI机制,因此在jdbc4及以后,可以不用显示的加载数据库驱动类;


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值