Dubbo之ExtensionLoader

dubbo是高度可扩展,用户几乎可以在任何功能点进行自定义实现。而这些高扩展性,得益于ExtensionLoader的实现。
下面我们一起分析下ExtensionLoader。

什么是ExtensionLoader

先来看下ExtensionLoader类的注释

/**
 * Load dubbo extensions
 * <ul>
 * <li>auto inject dependency extension </li>
 * <li>auto wrap extension in wrapper </li>
 * <li>default extension is an adaptive instance</li>
 * </ul>
 */
public class ExtensionLoader<T> {
}

简单翻译下:
加载dubbo扩展

  • 自动注入依赖扩展
  • 自动封装扩展
  • 默认扩展是一个可适应的实例

光看注释,其实我们还是没法知道ExtensionLoader到底是什么?还是得通过例子来理解。

一个简单例子

public static void main(String[] args) throws IOException {
    ExtensionLoader<Protocol> extensionLoader = ExtensionLoader.getExtensionLoader(Protocol.class);
    Protocol protocol = extensionLoader.getExtension("dubbo");
    System.out.println(protocol);
}

输出:
com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper@3fee9989

怎么输出了ProtocolFilterWrapper,而不是DubboProtocol?

ExtensionLoader.getExtensionLoader(Protocol.class)

首先看下ExtensionLoader.getExtensionLoader(Protocol.class) 做了什么。

ExtensionLoader<T> loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
if (loader == null) {
    EXTENSION_LOADERS.putIfAbsent(type, new ExtensionLoader<T>(type));
    loader = (ExtensionLoader<T>) EXTENSION_LOADERS.get(type);
}
return loader;

将Protocol.class作为参数创建了ExtensionLoader

private ExtensionLoader(Class<?> type) {
    this.type = type;
    objectFactory = (type == ExtensionFactory.class ? null : ExtensionLoader.getExtensionLoader(ExtensionFactory.class).getAdaptiveExtension());
}

ExtensionLoader有两个成员变量,type是我们传的Protocol.class,objectFactory是用来给生成的扩展对象属性赋值。
创建好ExtensionLoader后,放入EXTENSION_LOADERS中,再次获取可以从缓存中获取。

extensionLoader.getExtension(“dubbo”)

接下来,再看下extensionLoader.getExtension(“dubbo”),代码执行过程如下:
在这里插入图片描述
简单总结下上面的流程:

  • 根据loadDirectory方法从指定目录加载type全类名的文件;
  • 通过loadResource方法循环解析文件的每一行,以等号拆分,等号左边为name,右边为class;
  • 通过loadClass方法把解析出的class根据不同类型放入不同的缓存mapp中,比如wrapper类放入cachedWrapperClasses缓存。
  • 创建实例,通过injectExtension方法给实例属性赋值。

注解@Adaptive

Adaptive有什么用?
我们来看一个例子

public static void main(String[] args) throws IOException {
    ExtensionLoader<Serialization> extensionLoader = ExtensionLoader.getExtensionLoader(Serialization.class);
    Serialization serialization = extensionLoader.getAdaptiveExtension();
    System.out.println(serialization);
}

输出:
com.alibaba.dubbo.common.serialize.Serialization$Adaptive@276438c9

生成了一个新的类Serialization$Adaptive,我们先来看下Serialization的代码

@SPI("hessian2")
public interface Serialization {

    /**
     * get content type id
     *
     * @return content type id
     */
    byte getContentTypeId();

    /**
     * get content type
     *
     * @return content type
     */
    String getContentType();

    /**
     * create serializer
     *
     * @param url
     * @param output
     * @return serializer
     * @throws IOException
     */
    @Adaptive
    ObjectOutput serialize(URL url, OutputStream output) throws IOException;

    /**
     * create deserializer
     *
     * @param url
     * @param input
     * @return deserializer
     * @throws IOException
     */
    @Adaptive
    ObjectInput deserialize(URL url, InputStream input) throws IOException;

}

再对比下生成的新类Serialization$Adaptive,

public class Serialization$Adaptive implements com.alibaba.dubbo.common.serialize.Serialization {
    public byte getContentTypeId() {
        throw new UnsupportedOperationException("method public abstract byte com.alibaba.dubbo.common.serialize.Serialization.getContentTypeId() of interface com.alibaba.dubbo.common.serialize.Serialization is not adaptive method!");
    }

    public com.alibaba.dubbo.common.serialize.ObjectOutput serialize(com.alibaba.dubbo.common.URL arg0, java.io.OutputStream arg1) throws java.io.IOException {
        if (arg0 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg0;
        String extName = url.getParameter("serialization", "hessian2");
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.common.serialize.Serialization) name from url(" + url.toString() + ") use keys([serialization])");
        com.alibaba.dubbo.common.serialize.Serialization extension = (com.alibaba.dubbo.common.serialize.Serialization) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.serialize.Serialization.class).getExtension(extName);
        return extension.serialize(arg0, arg1);
    }

    public com.alibaba.dubbo.common.serialize.ObjectInput deserialize(com.alibaba.dubbo.common.URL arg0, java.io.InputStream arg1) throws java.io.IOException {
        if (arg0 == null) throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg0;
        String extName = url.getParameter("serialization", "hessian2");
        if (extName == null)
            throw new IllegalStateException("Fail to get extension(com.alibaba.dubbo.common.serialize.Serialization) name from url(" + url.toString() + ") use keys([serialization])");
        com.alibaba.dubbo.common.serialize.Serialization extension = (com.alibaba.dubbo.common.serialize.Serialization) ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.common.serialize.Serialization.class).getExtension(extName);
        return extension.deserialize(arg0, arg1);
    }

    public java.lang.String getContentType() {
        throw new UnsupportedOperationException("method public abstract java.lang.String com.alibaba.dubbo.common.serialize.Serialization.getContentType() of interface com.alibaba.dubbo.common.serialize.Serialization is not adaptive method!");
    }
}

从中可以发现

  • 没加@Adaptive的方法,直接抛出异常UnsupportedOperationException;
  • 加了注解的方法主要逻辑
    • 根据url获取参数中的扩展名extName
    • 再根据扩展名extName获取对应的扩展类

具体代码生成逻辑,有兴趣的可以看下源码实现

com.alibaba.dubbo.common.extension.ExtensionLoader#createAdaptiveExtensionClassCode

注解@Activate

最后看下Activate

public static void main(String[] args) throws IOException {
    URL url = URL.valueOf("test://localhost/test");
    List<Filter> list = ExtensionLoader.getExtensionLoader(Filter.class)
            .getActivateExtension(url, new String[]{}, Constants.CONSUMER);
    System.out.println(list);
}

输出:
[com.alibaba.dubbo.rpc.filter.ConsumerContextFilter@525b461a, com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter@58c1c010, com.alibaba.dubbo.monitor.support.MonitorFilter@b7f23d9]

ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(URL url, String[] values, String group),会把Filter.class实现类带@Activate注解且group为Constants.CONSUMER的获取到。
比如

@Activate(group = Constants.CONSUMER, order = -10000)
public class ConsumerContextFilter implements Filter {
}

Dubbo之ExtensionLoader的分享就到这里,有问题欢迎指出。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值