关于dubbo扩展点的一点分析

扩展点能力

  1. 能load class,这个class除了顶层接口class(在ExtensionLoader中对应type字段),还能load各实现类的class。
  2. 能创建instance。
  3. 能指定这个顶层接口的默认实现类的beanName。做法参见SPI注解部分。
  4. 能把创建出来的instance的字段注入。set开头的且有一个参数且是public的,注入。
  5. 能adaptive。根据url上对该接口配置的实现类,将该接口的事情交给这个实现类去做(我更多的理解成委托)。此能力采用代码生成再编译的方式。代码生成示例可以参见adaptive类代码示例。 adaptive只会生成一个adaptive实现类。生成代码的逻辑在com.alibaba.dubbo.common.extension.ExtensionLoader.createAdaptiveExtensionClassCode()
  6. 能wrapper。wrapper是指这个顶层接口的实现类的构造函数的入参是这个顶层接口类型。那么这个实现类称之为wrapper类,可以有多个,构建instance时不分多个之间的顺序。因为用来给构造函数传参的instance是这个顶层类的默认实现。比如com.alibaba.dubbo.rpc.Protocol接口,有实现类 com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol beanName是injvm,QosProtocolWrapper、ProtocolListenerWrapper、ProtocolFilterWrapper是其三个wrapper类。创建warpper instance的代码逻辑在com.alibaba.dubbo.common.extension.ExtensionLoader.createExtension(String)中。
  7. 能active。实现类加了Activate注解的。在ExtensionLoader.getActivateExtension时会根据当前的url(配置信息)中值来匹配Activate注解中指定的值是否能match,能match的表示是activate,意思是命中的。在过滤器扩展点中用到。比如这个过滤器是给CONSUMER group用。示例有ExceptionFilter等。同时该注解还能支持order属性来定义bean的顺序。

扩展点使用

配置文件相关

配置文件放在哪里?

  1. META-INF/dubbo/internal/配置文件
  2. META-INF/dubbo/配置文件
  3. META-INF/services/配置文件

配置文件名是顶层接口全限定名,比如:com.alibaba.dubbo.rpc.Protocol

配置文件中内容:
一行是一个实现类的定义,大致是
beanName=实现类的class的全限定名,这个后面还可以接上#xxx(这个能力实际使用少)。beanName=这部分不是必须的。可以仅仅写实现类的全限定名。

注解相关

SPI

SPI注解用在顶层接口上,其值表示这个接口的默认实现类的beanName,也即是说指定一个顶层接口的默认实现通过SPI注解加载顶层接口上指定即可。

Adaptive

Adaptive注解用在顶层接口或者接口的方法上,其表示这个接口或者这个方法需要有adaptive的类委托完成,未加注解的会生成不支持的操作的方式实现。

Activate

Activate注解用在实现类上,其表示实现类在rpc时根据url参数中以及注解中指定的key 目标value是否能匹配来决定此bean是否被选中(一般用在过滤器的命中判断上)。

生成的代码

adaptive类代码示例

package com.alibaba.dubbo.registry;

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

public class RegistryFactory$Adaptive implements com.alibaba.dubbo.registry.RegistryFactory {
    public com.alibaba.dubbo.registry.Registry getRegistry(com.alibaba.dubbo.common.URL arg0) {
        if (arg0 == null)
            throw new IllegalArgumentException("url == null");
        com.alibaba.dubbo.common.URL url = arg0;
        String extName = (url.getProtocol() == null ? "dubbo" : url.getProtocol());
        if (extName == null)
            throw new IllegalStateException(
                    "Fail to get extension(com.alibaba.dubbo.registry.RegistryFactory) name from url(" + url.toString()
                            + ") use keys([protocol])");
        com.alibaba.dubbo.registry.RegistryFactory extension = (com.alibaba.dubbo.registry.RegistryFactory) ExtensionLoader
                .getExtensionLoader(com.alibaba.dubbo.registry.RegistryFactory.class).getExtension(extName);
        return extension.getRegistry(arg0);
    }
}
package com.alibaba.dubbo.rpc.cluster;

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

public class Cluster$Adaptive implements com.alibaba.dubbo.rpc.cluster.Cluster {
    public com.alibaba.dubbo.rpc.Invoker join(com.alibaba.dubbo.rpc.cluster.Directory arg0)
            throws com.alibaba.dubbo.rpc.RpcException {
        if (arg0 == null)
            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.cluster.Directory argument == null");
        if (arg0.getUrl() == null)
            throw new IllegalArgumentException("com.alibaba.dubbo.rpc.cluster.Directory argument getUrl() == null");
        com.alibaba.dubbo.common.URL url = arg0.getUrl();
        String extName = url.getParameter("cluster", "failover");
        if (extName == null)
            throw new IllegalStateException(
                    "Fail to get extension(com.alibaba.dubbo.rpc.cluster.Cluster) name from url(" + url.toString()
                            + ") use keys([cluster])");
        com.alibaba.dubbo.rpc.cluster.Cluster extension = (com.alibaba.dubbo.rpc.cluster.Cluster) ExtensionLoader
                .getExtensionLoader(com.alibaba.dubbo.rpc.cluster.Cluster.class).getExtension(extName);
        return extension.join(arg0);
    }
}

杂项

查找所有的dubbo扩展点形式的配置文件

find ./ -type f -name "com.alibaba.dubbo*"|grep -v "/target/"|grep -v "/bin/"|grep -v "/test/"

另:
关于代理模式,dubbo未实现通用的,只是rpc语义实现里rpc调用的代理,借助扩展点机器加动态代理完成。
具体其顶层接口是com.alibaba.dubbo.rpc.ProxyFactory。用在比如将EchoService编织进每次RPC调用中。

猜你喜欢

转载自www.cnblogs.com/simoncook/p/12310071.html