Dubbo-扩展机制-SPI
SPI 全称为 Service Provider Interface,是一种服务发现机制
一、Java SPI

从上面可以看出Java中的SPI最大的缺点是会加载一些不必要的组件。
二、Dubbo SPI
(1)基本原理
Dubbo在某个接口上加上@SPI注解后,表明该接口为可扩展接口
ExtensionLoader类是扩展加载器,这是dubbo实现SPI扩展机制等核心,几乎所有实现的逻辑都被封装在ExtensionLoader中

示例代码
@SPI("alipay")
public interface PayService {
void pay(double price);
}
public class AlipayService implements PayService {
@Override
public void pay(double price) {
System.out.println("使用支付宝支付" + price + "元");
}
}
public class WechatPayService implements PayService {
public void pay(double price) {
System.out.println("使用微信支付" + price + "元");
}
}在/resources/META-INF/services/目录下有个文件com.test.PayService,内容如下:
wechatPay = com.test.WechatPayService alipay = com.test.AlipayService
测试
public static void main(String[] args) {
ExtensionLoader<PayService> extensionLoader = ExtensionLoader.getExtensionLoader(PayService.class);
PayService wechatPay = extensionLoader.getExtension("wechatPay");
wechatPay.pay(20);
PayService alipay = extensionLoader.getExtension("alipay");
alipay.pay(20);
}(2)Dubbo中的使用(间接调用)
Dubbo 就是通过 SPI 机制加载所有的组件,但是Dubbo中一般不直接通过extensionLoader.getExtension("alipay") 方法来调用,而是动态适配的,即通过Adaptive实现,下个章节再讲。下面以ProxyFactory为例
ProxyFactory是一个接口,在其接口上使用了@SPI注解,并默认赋值为javassist
@SPI("javassist") // 默认
public interface ProxyFactory {...}在 /dubbo-rpc-api/src/main/resources/META-INF/dubbo/internal 目录下有一个com.alibaba.dubbo.rpc.ProxyFactory 文件,文件内容如下
stub=com.alibaba.dubbo.rpc.proxy.wrapper.StubProxyFactoryWrapper jdk=com.alibaba.dubbo.rpc.proxy.jdk.JdkProxyFactory javassist=com.alibaba.dubbo.rpc.proxy.javassist.JavassistProxyFactory
Dubbo间接使用的地方,如ReferenceConfig类创建代理对象的过程
public class ReferenceConfig<T> extends AbstractReferenceConfig {
private static final ProxyFactory proxyFactory = ExtensionLoader.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
...
private T createProxy(Map<String, String> map) {
...
// 该方法的最后一行
return (T) proxyFactory.getProxy(invoker);
}
...
}proxyFactory 会通过ExtensionLoader,再调用getAdaptiveExtension方法,会生成一个ProxyFactory$Adaptive类。
public java.lang.Object getProxy(com.alibaba.dubbo.rpc.Invoker arg0) throws com.alibaba.dubbo.rpc.RpcException {
if (arg0 == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument == null");
if (arg0.getUrl() == null)
throw new IllegalArgumentException("com.alibaba.dubbo.rpc.Invoker argument getUrl() == null");
com.alibaba.dubbo.common.URL url = arg0.getUrl();
// 1.从 URL 中获取指定的SPI的扩展名称,proxy
String extName = url.getParameter("proxy", "javassist");
if(extName == null)
throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.ProxyFactory) name from url("
+ url.toString() + ") use keys([proxy])");
// 2.通过 SPI 加载具体的实现类
com.alibaba.dubbo.rpc.ProxyFactory extension = (com.alibaba.dubbo.rpc.ProxyFactory)ExtensionLoader
.getExtensionLoader(com.alibaba.dubbo.rpc.ProxyFactory.class).getExtension(extName);
// 3.调用目标方法
return extension.getProxy(arg0);
}步骤2则是真正调用的地方。
相关推荐
大步流星 2020-06-05
supperme 2020-09-08
doctorvian 2020-08-02
aNian 2020-08-01
kongjunlongaa 2020-06-29
Fightingxr 2020-06-26
whileinsist 2020-06-24
XuNeely 2020-06-16
wangyangsoftware 2020-06-16
大步流星 2020-06-16
aNian 2020-06-16
gaoyongstone 2020-06-16
MartellJenkins 2020-06-11
范群松 2020-06-11
Fightingxr 2020-06-08
XuNeely 2020-06-07
gaoyongstone 2020-06-05