Java SPI与Dubbo SPI

本文详细介绍了Java原生的SPI(Service Provider Interface)机制,包括接口实现、配置与原理。接着探讨了Dubbo如何增强SPI,通过@SPI注解实现更灵活的接口选择,并分析了Dubbo SPI的加载流程和缓存策略,指出其相比原生SPI的优越性。

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

Java原生SPI

面向接口编程+策略模式

实现
建立接口

Robot

public interface Robot {
   
    /**
     * 测试方法1
     */
    void sayHello();
}
多个实现类实现接口

RobotA

public class RobotA implements Robot {
    public RobotA() {
        System.out.println("Happy RobotA is loaded");
    }
    @Override
    public void sayHello() {
        System.out.println("i am a very very happy Robot ");
    }
    public void sayBye(){}
}

RobotB

public class RobotB implements Robot {
   
    public RobotB() {
   
        System.out.println("SB RobotB is loaded");
    }
    @Override
    public void sayHello() {
   
        System.out.println("i am a da sha bi ");
    }
    public void sayBye(){
   }
}
配置实现类与接口

META-INF/services目录下建立一个以接口全限定名为名字的文件,里面的内容是实现类的全限定名

原理

通过ServiceLoader与配置文件中的全限定名加载所有实现类,根据迭代器获取具体的某一个类

我们通过对下面一段代码的分析来说明

ServiceLoader<Robot> serviceLoader=ServiceLoader.load(Robot.class);
serviceLoader.forEach(Robot::sayHello);

load(Robot.class)这个方法的目的只是为了设置类加载器为线程上下文加载器,我们当然可以不这么做,直接调用load(Class service,ClassLoader loader)方法

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

这个load方法其实也没有做什么实质的事,仅仅是实例化了一个ServiceLoad对象返回罢了

public static <S> ServiceLoader<S> load(Class<S> service,
                                        ClassLoader loader)
{
    return new ServiceLoader<>(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() {
    //这里的provider是一个对于已实例化对象的缓存,为Map类型
        providers.clear();
        lookupIterator = new LazyIterator(service, loader);
    }

没有,这里仅仅只是检验了参数和权限这样一些准备操作.然后实例化了一个LazyIterator

这是LazyIterator的构造函数

private LazyIterator(Class<S> service, ClassLoader loader) {
    this.service = service;
    this.loader = loader;
}

然后…,没了,ServiceLoader<Robot> serviceLoader=ServiceLoader.load(Robot.class);执行完毕了,到这里,并没有实例化我们所需要的Robot对象,而仅仅只是返回了一个ServiceLoader对象

这时候如果我们去看serviceLoader的对象方法是这样的

有用的只有这三个方法,reload上面已经提到过,只是重新实例化一个对象而已.

而另外两个iterator()是个迭代器,foreach也只是用于迭代的语法糖罢了.如果我们debug的话,会发现foreach的核心依旧会变成iterator(),好了,接下来重点看iterator()

public Iterator<S> iterator() {
   
    return new Iterator<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值