dubbo SPI的实现过程

1. 问题

   dubbo的自适应类加载机制是如何实现的? 例如,Protocol的实现类是如何加载的 

// 如何解析
    private static final Protocol REF_PROTOCOL = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension();

 2. 解析过程

getAdaptiveExtension() ---> createAdaptiveExtension()--->
getAdaptiveExtensionClass()--->
getExtensionClasses()---> 
loadExtensionClasses()
createAdaptiveExtensionClass()--->
  private Class<?> createAdaptiveExtensionClass() {
        String code = (new AdaptiveClassCodeGenerator(this.type, this.cachedDefaultName)).generate();
        ClassLoader classLoader = findClassLoader();
        Compiler compiler = (Compiler)getExtensionLoader(Compiler.class).getAdaptiveExtension();
        return compiler.compile(code, classLoader);
    }

 获取dubbo.jar的META-INF/dubbo目录下指定的文件

  private Map<String, Class<?>> loadExtensionClasses() {
        this.cacheDefaultExtensionName();
        Map<String, Class<?>> extensionClasses = new HashMap();
        this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName());
        this.loadDirectory(extensionClasses, "META-INF/dubbo/internal/", this.type.getName().replace("org.apache", "com.alibaba"));
        this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName());
        this.loadDirectory(extensionClasses, "META-INF/dubbo/", this.type.getName().replace("org.apache", "com.alibaba"));
        this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName());
        this.loadDirectory(extensionClasses, "META-INF/services/", this.type.getName().replace("org.apache", "com.alibaba"));
        return extensionClasses;
    }

获取接口定义信息中的默认扩展名 

private void cacheDefaultExtensionName() {
        SPI defaultAnnotation = (SPI)this.type.getAnnotation(SPI.class);
        if (defaultAnnotation != null) {
            String value = defaultAnnotation.value();
            if ((value = value.trim()).length() > 0) {
                String[] names = NAME_SEPARATOR.split(value);
                if (names.length > 1) {
                    throw new IllegalStateException("More than 1 default extension name on extension " + this.type.getName() + ": " + Arrays.toString(names));
                }

                if (names.length == 1) {
                    this.cachedDefaultName = names[0];
                }
            }
        }

    }

 默认选择的实现类

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

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

    @Adaptive
    <T> Invoker<T> refer(Class<T> var1, URL var2) throws RpcException;

    void destroy();
}

自动生成的DubboProtocol代码

动态生成代码 

StringBuilder code = new StringBuilder();
code.append(this.generatePackageInfo());  // 包名
code.append(this.generateImports());      // import
code.append(this.generateClassDeclaration()); // 类定义
Method[] methods = this.type.getMethods();    // 方法,来自接口的定义,实现这些接口
Method[] var3 = methods;
int var4 = methods.length;

for(int var5 = 0; var5 < var4; ++var5) {
    Method method = var3[var5];
    code.append(this.generateMethod(method));   // 方法的实现
} 
 private String generateMethod(Method method) {
        String methodReturnType = method.getReturnType().getCanonicalName();
        String methodName = method.getName();
        String methodContent = this.generateMethodContent(method);
        String methodArgs = this.generateMethodArguments(method);
        String methodThrows = this.generateMethodThrows(method);
        return String.format("public %s %s(%s) %s {\n%s}\n", methodReturnType, methodName, methodArgs, methodThrows, methodContent);
    }

 最终生成的代码如下: 

package org.apache.dubbo.rpc;

import org.apache.dubbo.common.extension.ExtensionLoader;

public class Protocol$Adaptive implements org.apache.dubbo.rpc.Protocol {
    public void destroy() {
        throw new UnsupportedOperationException("The method public abstract void org.apache.dubbo.rpc.Protocol.destroy() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public int getDefaultPort() {
        throw new UnsupportedOperationException("The method public abstract int org.apache.dubbo.rpc.Protocol.getDefaultPort() of interface org.apache.dubbo.rpc.Protocol is not adaptive method!");
    }

    public org.apache.dubbo.rpc.Invoker refer(java.lang.Class arg0, org.apache.dubbo.common.URL arg1) throws org.apache.dubbo.rpc.RpcException {
        if (arg1 == null) throw new IllegalArgumentException("url == null");
        org.apache.dubbo.common.URL url = arg1;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }

    public org.apache.dubbo.rpc.Exporter export(org.apache.dubbo.rpc.Invoker arg0) throws org.apache.dubbo.rpc.RpcException {
        if (arg0 == null) throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("org.apache.dubbo.rpc.Invoker argument getUrl() == null");
        org.apache.dubbo.common.URL url = arg0.getUrl();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Failed to get extension (org.apache.dubbo.rpc.Protocol) name from url (" + url.toString() + ") use keys([protocol])");
        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }
}

        org.apache.dubbo.rpc.Protocol extension = (org.apache.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(org.apache.dubbo.rpc.Protocol.class).getExtension(extName);

 

 public T getExtension(String name) {
        if (StringUtils.isEmpty(name)) {
            throw new IllegalArgumentException("Extension name == null");
        } else if ("true".equals(name)) {
            return this.getDefaultExtension();
        } else {
            Holder<Object> holder = this.getOrCreateHolder(name);
            Object instance = holder.get();
            if (instance == null) {
                synchronized(holder) {
                    instance = holder.get();
                    if (instance == null) {
                        instance = this.createExtension(name);
                        holder.set(instance);
                    }
                }
            }

            return instance;
        }
    }
 private T createExtension(String name) {
        Class<?> clazz = (Class)this.getExtensionClasses().get(name); //  加载META-INF/dubbo
        if (clazz == null) {
            throw this.findException(name);
        } else {
            try {
                T instance = EXTENSION_INSTANCES.get(clazz);
                if (instance == null) {
                    EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance()); // 实例化
                    instance = EXTENSION_INSTANCES.get(clazz);
                }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值