• 关于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调用中。

  • 相关阅读:
    jQuery 属性操作
    Codeforces Round #679 (Div. 2, based on Technocup 2021 Elimination Round 1) (个人题解)
    (模板)graham扫描法、andrew算法求凸包
    POJ
    Codeforces Round #677 (Div. 3) (A
    第十三场训练赛
    [kuangbin] 专题13 基础计算几何 题解 + 总结
    特殊的数据结构:主席树
    【计算几何03】距离计算
    Java实现 LeetCode 803 打砖块 (DFS)
  • 原文地址:https://www.cnblogs.com/simoncook/p/12310071.html
Copyright © 2020-2023  润新知