JAVA SPI 机制到底是什么?DUBBO SPI有什么不同?

JAVA SPI 机制到底是什么?

SPI (Service Provider Interface) 是一种将服务接口和服务实现分离的机制
这样一来便做到了降低耦合度增加可扩展性的目的,当然最重要的是实现了程序之间的可插拔,像jdbc的驱动加载,dubbo的实现,springBoot自动配置都是基于了spi这种机制,再次基础上加以扩展的.

java原生SPI实现:

创建一个接口与其的2个实现类:

public interface SpiInterface {
    /***
     * Description <br>
     *  方法调用
     **/
    void action();
}
public class OriginalImpl implements SpiInterface {
    @Override
    public void action() {
        System.out.println("OriginalImpl");
    }
}
public class DubboImpl implements SpiInterface {
    @Override
    public void action() {
        System.out.println("DubboImpl");
    }
}

在classpath下创建META-INF\services\ 目录(这个名称不能错,后面会解释)
将接口的全类名作为文件放入该目录下
在这里插入图片描述
将实现类全类名分行写入该文件中
在这里插入图片描述

编写测试类:

public class SpiTest {
    public static void main(String[] args) {
        ServiceLoader<SpiInterface> serviceLoader = ServiceLoader.load(SpiInterface.class);
        serviceLoader.forEach(SpiInterface::action);
    }
}

测试结果:
在这里插入图片描述

  • 可以看到使用java原生的spi虽然平没有显示实例化实现类但是将文件中的实现都实例化并调用了action打印了结果.
  • 分析下load()方法干了什么:
private static final String PREFIX = "META-INF/services/";

    // The class or interface representing the service being loaded
    private final Class<S> service;

    // The class loader used to locate, load, and instantiate providers
    private final ClassLoader loader;

    // The access control context taken when the ServiceLoader is created
    private final AccessControlContext acc;

    // Cached providers, in instantiation order
    private LinkedHashMap<String,S> providers = new LinkedHashMap<>();

    // The current lazy-lookup iterator
    private LazyIterator lookupIterator;
    public void reload() {
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }

    private ServiceLoader(Class<S> svc, ClassLoader cl) {
        service = Objects.requireNonNull(svc, "Service interface cannot be null");
        loader = (cl == null) ? ClassLoader.getSystemClassLoader() : cl;
        acc = (System.getSecurityManager() != null) ? AccessController.getContext() : null;
        reload();
    }

public void reload() {
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }
  1. 判断下是否传入了加载器,没有的话使用系统加载器,
  2. 接着回去调用reload方法而这个reload()又会去调用LazyIterator,其实也就是这是一个延迟的加载ServiceLoader.load().
  3. LazyIterator这个装载类的时候没有立马实例化我们需要的对象,而是等到调用迭代器的hasNext时候才回去实例化我们的接口实现对象,
  4. 具体怎么实现,因为读取的配置全类名,那么自然是使用的java反射调用构造器进行的实例化.

DUBBO的SPI

SPI在dubbo中也是有十分重要的使用体现,如dubbo调用策略的切换,使用协议的切换都依赖于SPI机制,而dubbo的SPI是在源生的SPI上做了扩展,弥补了源生SPI不能定向实例化的不足,还是使用之前的Service类,编写dubbo SPI测试类
注: 使用DUBBO SPI需要在接口加上@SPI注解

@SPI
public interface SpiInterface {
    /***
     * Description <br>
     *  方法调用
     **/
    void action();
}

在classpath下创建META-INF\dubbo\ 目录,将接口的全类名作为文件放入该目录下 将实现类全类名以key-value分行写入该文件中
在这里插入图片描述
在这里插入图片描述

测试类:

public class DubboSpiTest {
    public static void main(String[] args) {
        ExtensionLoader<SpiInterface> extensionLoader = ExtensionLoader.getExtensionLoader(SpiInterface.class);
        SpiInterface dubbo = extensionLoader.getExtension("dubbo");
        SpiInterface original = extensionLoader.getExtension("original");
        dubbo.action();
        original.action();
    }
}
  • dubbo的SPI是使用ExtensionLoader扩展了java源生的SPI,可以实现以key-value的形式加载接口实现类.
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值