dubbo系列之内核SPI-Protocol扩展类生成(九)

252 阅读4分钟

欢迎关注公众号【sharedCode】致力于主流中间件的源码分析, 可以直接与我联系

博主个人网站:www.shared-code.com

前文回顾

上一篇文章我们讲到,扩展实现类的类上如果写上了@Adaptive注解,则可以直接取得扩展实现类对象,其他的需要通过字节码生成技术来生成对象,接着上文的代码讲解,调用createAdaptiveExtensionClass方法生成扩展实现类对象

createAdaptiveExtensionClass

private Class<?> createAdaptiveExtensionClass() {
  		// 获取扩展实现类的代码code, 这个类里面是拼接的字符穿
        String code = createAdaptiveExtensionClassCode();
  		// 获取类加载器
        ClassLoader classLoader = findClassLoader();
  		// 字节码生成对象。
        com.alibaba.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
  		// 通过字节码工具类,生成对象
        return compiler.compile(code, classLoader);
    }

createAdaptiveExtensionClassCode

这个代码非常长 ,大家看个大概就可以了。我也是为了帮助自己理解,看下他的这个类是怎么拼接的。

private String createAdaptiveExtensionClassCode() {
  		// 构建一个字符创拼接对象
        StringBuilder codeBuilder = new StringBuilder();
  		// 获取实现了SPI接口的方法
        Method[] methods = type.getMethods();
  		// 方法上是否有@Adaptive注解
        boolean hasAdaptiveAnnotation = false;
        for (Method m : methods) {
          	// 判断方法上是否有Adaptive注解
            if (m.isAnnotationPresent(Adaptive.class)) {
                hasAdaptiveAnnotation = true;
                break;
            }
           //
        }
        //如果没有方法的头上有Adaptive注解 , 那么直接不通过,因为这里是给带有Adaptive注解的方法生成代理对象
        if (!hasAdaptiveAnnotation)
            throw new IllegalStateException("No adaptive method on extension " + type.getName() + ", refuse to create the adaptive class!");

        codeBuilder.append("package ").append(type.getPackage().getName()).append(";");  // 报名
        codeBuilder.append("\nimport ").append(ExtensionLoader.class.getName()).append(";");  // 导入包
        codeBuilder.append("\npublic class ").append(type.getSimpleName()).append("$Adaptive").append(" implements ").append(type.getCanonicalName()).append(" {");  // 定义类名

        for (Method method : methods) {
            Class<?> rt = method.getReturnType(); // 方法的返回值类型
            Class<?>[] pts = method.getParameterTypes();  // 方法的入参 类型集合
            Class<?>[] ets = method.getExceptionTypes();  // 方法抛出的异常集合

            // 代码省略。。
        }
        codeBuilder.append("\n}");
        if (logger.isDebugEnabled()) {
            logger.debug(codeBuilder.toString());
        }
        return codeBuilder.toString();
    }

代码太长了,我就不贴了,最终生成的字符串如下:

package com.alibaba.dubbo.rpc;

import com.alibaba.dubbo.common.extension.ExtensionLoader;

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

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

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

    public com.alibaba.dubbo.rpc.Exporter export(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();
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.rpc.Protocol) name from url(" + url.toString() + ") use keys([protocol])");
        // 重点在这里。。。
        com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }
}

扩展实现类名称, 是否还记得Protocol.class类上的SPI注解,该注解里面指定了Protocol的协议类型为dubbo, 因此,在这里,如果说,传入的参数中没有动态指定其他的协议类型的话,那么默认的协议类型就是dubbo, 也就是说dubbo允许在运行过程中使用其他的协议类型,

String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());

上面的扩展实现类,最重要的一行代码,就是

com.alibaba.dubbo.rpc.Protocol extension = (com.alibaba.dubbo.rpc.Protocol) ExtensionLoader.getExtensionLoader(
  com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName)

之前SPI的第一篇文章我们了解到,ExtensionLoader.getExtensionLoader 这个方法中 , 针对ExtensionLoader的创建仅限在第一次,第二次获取,会直接从缓存中获取,因此不存在性能问题。 关键在于getExtension,这个方法我们之前没有了解过,下面看一下这个方法的实现。

getExtension

public T getExtension(String name) {
  		// 判断扩展名称不为空。
        if (name == null || name.length() == 0)
            throw new IllegalArgumentException("Extension name == null");
  		// 如果名称等于true的话,那么直接返回默认的扩展实现类
        if ("true".equals(name)) {
            return getDefaultExtension();
        }
        // 从缓存中获取当前name所属的Holder
        Holder<Object> holder = cachedInstances.get(name);
        if (holder == null) {
          	// 不存在,则创建一个Holder
            cachedInstances.putIfAbsent(name, new Holder<Object>());
            holder = cachedInstances.get(name);
        }
  		// 获取holder里面包含的实例信息
        Object instance = holder.get();
        if (instance == null) { 
            // 实例信息为空
            synchronized (holder) {
              	// 加上锁进行同步
                instance = holder.get();
                if (instance == null) { // 再次判断视为为空,,双重检查。
                  	// 创建实例、
                    instance = createExtension(name);
                    holder.set(instance);
                }
            }
        }
        return (T) instance;
    }

createExtension

private T createExtension(String name) {
  		// 从getExtensionClasses中根据当前名称获取实例信息
        Class<?> clazz = getExtensionClasses().get(name);
        if (clazz == null) {
          	// 找不到,则说明当前传入的扩展名称,没有在SPI扩展文件中存在
            throw findException(name);
        }
        try {
          	// 从缓存map中获取实例想你想
            T instance = (T) EXTENSION_INSTANCES.get(clazz);
            if (instance == null) {
              	// 为空,则进行实例化,并放入map中。
                EXTENSION_INSTANCES.putIfAbsent(clazz, clazz.newInstance());
                instance = (T) EXTENSION_INSTANCES.get(clazz);
            }
          	// 进行依赖注入,这个在上文中是讲过的。
            injectExtension(instance);
          	// 装饰器类,用来增加扩展实现。
            Set<Class<?>> wrapperClasses = cachedWrapperClasses;
            if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
                for (Class<?> wrapperClass : wrapperClasses) {
                    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
                }
            }
            return instance;
        } catch (Throwable t) {
            throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
                    type + ")  could not be instantiated: " + t.getMessage(), t);
        }
    }

getExtensionClasses()方法返回的map数据如下,以Protocol为例

filter : com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener : com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
mock : com.alibaba.dubbo.rpc.support.MockProtocol
dubbo : com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol
injvm : com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol
rmi : com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol
hessian : com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol
com.alibaba.dubbo.rpc.protocol.http.HttpProtocol
com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol
thrift : com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol
memcached : com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol
redis : com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol
rest : com.alibaba.dubbo.rpc.protocol.rest.RestProtocol
registry : com.alibaba.dubbo.registry.integration.RegistryProtocol
qos : com.alibaba.dubbo.qos.protocol.QosProtocolWrapper

通过"dubbo"获取到的就是com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol实例。

在上面的代码中有几行代码比较重要,关系到后面的代码阅读

Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && !wrapperClasses.isEmpty()) {
  for (Class<?> wrapperClass : wrapperClasses) {
    instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
  }
}

获取到缓存起来的cachedWrapperClasses , Protocol的装饰器类有下面三个

class com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper
class com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
class com.alibaba.dubbo.qos.protocol.QosProtocolWrapper

也就是说DubboProtocol要经过这三个类进行装饰,包装之后返回,由于cachedWrapperClasses是一个CurrentHashSet ,所以他内部是不保证顺序的。 Wrapper类进行装饰的顺序是不一致的,所以最终instance返回的有可能是ProtocolListenerWrapper ProtocolFilterWrapper QosProtocolWrapper 中的任何一个,这个一定要注意,后面看服务暴露的代码的时候,首先要经过这三个类,最后才会执行DubboProtocol。

欢迎关注公众号【sharedCode】致力于主流中间件的源码分析, 可以直接与我联系

博主个人网站:www.shared-code.com