Dubbo基础---Java SPI

       SPI即Service Provider Interface, 服务提供接口;

       

       SPI是在面向接口编程的背景下产生的,  调用方只关心函数入参、返回值, 不关心函数实现;在编码中调用方不用加载实现类, 从而实现了热插拔。


SPI规则:

1、定义接口类;

2、创建/resources/META-INF/接口类  文件;

3、在文件中添加实现类的完整类名;

创建接口:

public interface IService {
    void doSomeThing();
}

定义多种实现:

public class HiService implements IService {
    @Override
    public void doSomeThing() {
        System.out.println("HiService is called");
    }
}
public class HelloService implements IService {
    @Override
    public void doSomeThing() {
        System.out.println("HelloService is called");
    }
}


在resources/META-INF/services目录下创建com.spitest.IService文件, 并编辑内容为

com.spitest.impl.HelloService
com.spitest.impl.HiService


使用ServicLoader加载实现类:

public class Main {
    public static void main(String[] args) {
        ServiceLoader<IService> services = ServiceLoader.load(IService.class);

        services.forEach( (item) -> {
            item.doSomeThing();  
        });
    }
}
输出:

HelloService is called
HiService is called


查看ServiceLoader源码, 通过Class.forName加载实现类后使用newInstance实例化。



META/services目录名称是写死的, 且目录下的文件必须以类完整名称命名, 因为代码里用getName函数。


可以看出SPI的好处是解耦接口类、实现类, 即实现了热插拔原则, 编译时不需要引用实现类。


在Dubbo源码里定义了SPI注解, 配置文件使用key=value的方式; 凡是使用@SPI的接口都会在/META-INF/dubbo/internal目录里读取实现类。

public @interface SPI {

    /**
     * default extension name
     */
    String value() default "";

}

例如:

@SPI("dubbo")
public interface Protocol {
    int getDefaultPort();

    @Adaptive
    <T> Exporter<T> export(Invoker<T> invoker) throws RpcException;

    @Adaptive
    <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException;

    void destroy();

}
对应/META-INF/dubbo/internal/com.alibaba.dubbo.rpc.Protocol文件,内容为

dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
   key=value格式的好处是如果某个实现类加载失败, 可以明确的指出来。 SPI.java里注解也做了说明:

If there's third party library referenced by static field or by method in extension implementation, its class will fail to initialize if the third party library doesn't exist. In this case, dubbo cannot figure out extension's id, therefore cannot be able to map the exception information with the extension, if the previous format is used.

有@SPI注解的接口类会依次在下面目录查找

/META-INF/dubbo/internal/

/META-INF/dubbo/

/META-INF/services/

     Dubbo自定义了ExtensionLoader类, 用于替换JDK的ServiceLoader。


   在启动服务时ExtensionLoader会读取3个目录


    可以运行一下dubbo-demo, 并在ExtensionLoader中多打一些断点就可以看出加载过程和参数定义;




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值