dubbo扩展点

  一.目的:

   使用者能够不改dubbo项目的情况下,在应用项目中增加相应类及配置就可以实现扩展。


  二.类似jdk的spi,但比jdk spi有以下优势:

  1.jdk的spi默认会加载并实例化所有扩展点类,如果对应扩展点没用到且实例化消耗大,则是个耗资源的点。

  2.不支持依赖注入,即如果在扩展点类a中,有b扩展点属性实例,则在加载扩展点类a时不会自动注入b。

  3.加载扩展点失败会吞掉异常,比如加载一个扩展类a,如果其所依赖的jar找不到,不会报这个错误,反而会报不支持。


  三.实现原理:

  有个核心的ExtensiontLoader用于加载扩展点。

  dubbo规定,protocal, filter, transport等都存在独立的ExtensionLoader。

  注入使用的时候,对应扩展点类是织入相应字节码的类,主要是为了实现运行时动态根据调用的url相应参数去查找具体的扩展点实现类。

  protocal实现类:

   会生成以下类:

 

class Protocol$Adpative implements Protocol{
    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)com.alibaba.dubbo.common.ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.export(arg0);
    }

    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)com.alibaba.dubbo.common.ExtensionLoader.getExtensionLoader(com.alibaba.dubbo.rpc.Protocol.class).getExtension(extName);
        return extension.refer(arg0, arg1);
    }

    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!");
    }
}

  这里可以看到,主要是实现了根据url的protocal属性去查找对应的扩展点实现类。

  默认实现类优先取Adaptive标注上对应key的扩展点类。取不到则取spi标注上对应类。

  

  四.使用示例:

  增加一个dubbo方法执行时间log。

  这里通过增加一个filter来解决,dubbo提供了fiter扩展点。

  需要进行以下步骤:

  1.创建filter类

    这里是:XxxFilter


  2.建立以下目录及文件

   这里的META-INF, dubbo及 com.alibaba.dubbo.rpc.Filter文件,里面有对应内容:

     

xxx=com.xxx.XxxFilter

注:这里的xxx在用到的地方引用即可。比如在服务提供方上加入:
然后扩展点加载类就会加载【com.alibaba.xxx.XxxFilter

    

·

    

 3.在使用的地方引用上述的【xxx】

   

在服务提供方上加入: ,这里的xxx是对应扩展点目录文件内容中对应key值。
然后扩展点加载类就会加载【com.alibaba.xxx.XxxFilter

  

 五.dubbo filter原理 

   dubbo在暴露服务时,会对invoker做一层封装,使得filter能够正常执行。

   比如存在:a,b,c三个filter,要执行的inovker是target。

   则会形成链表:a->b->c->target

  最终这个target对应服务被调用时,会依次执行a,b,c,target。

  



你可能感兴趣的:(dubbo)