博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Dubbo 拦截器和监听器
阅读量:6545 次
发布时间:2019-06-24

本文共 4139 字,大约阅读时间需要 13 分钟。

  hot3.png

今天要聊一个可能被其他dubbo源码研究的童鞋容易忽略的话题:Filter和Listener。

我们先来看一下这两个概念的官方手册:

  • 监听器:和

老实说,依赖之前的源码分析经验,导致我饶了很大的弯路,一直找不到filterlistener被使用的位置。看过前几篇文章的朋友应该也有这个疑惑,为什么按照url参数去匹配框架的执行流程,死活找不到dubbo注入拦截器和监听器的位置呢?

ReferenceConfig -->  RegistryProtocol --> DubboProtocol  -->  invoker  -->  exporter

按照这个调用流程,没错啊,可每一个环节都没有使用filterlistener属性的痕迹,有点抓瞎了啊。要说用好IDE确实很重要啊,光靠脑子想真的很伤身,下面来看一下谜底。

先来回忆一下dubbo的SPI机制,根据接口类型,dubbo会去读取并解析对应的配置文件,从中拿到对应的扩展点实现,好,我们先来看一下Protocol接口对应的配置文件:

registry=com.alibaba.dubbo.registry.integration.RegistryProtocoldubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol            filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper            #注意这一行listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper        #注意这一行mock=com.alibaba.dubbo.rpc.support.MockProtocolinjvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocolrmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocolhessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocolcom.alibaba.dubbo.rpc.protocol.http.HttpProtocolcom.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocolthrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocolmemcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocolredis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocolrest=com.alibaba.dubbo.rpc.protocol.rest.RestProtocol

我们已经找到了filterlistener对应的扩展点了。接下来看一下它们是怎么一步一步的被注入到上面的流程里的。

ReferenceConfig类中我们会引用和暴露对应的服务,我们以服务引用为场景来分析:

get()  -->  init()  -->   createProxy()                                |                                +--->  invoker = refprotocol.refer(interfaceClass, urls.get(0));

注意上面提到的这一行代码,这里的refprotocol是引用的Protocol$Adpative,这个类是dubbo的SPI机制动态创建的自适应扩展点,我们在之前的文章中已经介绍过,看一下它的refer方法细节:

public com.alibaba.dubbo.rpc.Invoker refer(java.lang.Class arg0, com.alibaba.dubbo.common.URL arg1) throws java.lang.Class {    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])");    //注意这一行,根据url的协议名称选择对应的扩展点实现    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);}

乍一看,并没有感觉有什么蹊跷,不过在单步调试中就会出现”诡异”现象(由于该类是动态创建的,所以该方法并不会被单步到,所以为分析带来了一定的干扰),我们得再往回倒一下,之前在中曾经分析过ExtensionLoader的源码,但是当时由于了解的不够确实忽略了一些细节。

我们再来看一下它的执行流程:

getExtension()  -->  createExtension()                            |                            +-->      ......                                    Set
> wrapperClasses = cachedWrapperClasses; if (wrapperClasses != null && wrapperClasses.size() > 0) { for (Class
wrapperClass : wrapperClasses) { //装饰器模式 instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance)); } } ......

一看到这行代码,就知道关键点在这里,这种写法刚好就是和常见的拦截器和监听器的实现方法吻合,而且事实证明也确实是在这个地方完成的注入,那么我们就需要看一下这个cachedWrapperClasses到到底存了什么?

我们最后看一下ExtensionLoader.loadFile方法,它是负责解析我们开头提到的那个SPI扩展点配置文件的,它会依次扫描配置文件的每一行,然后根据配置内容完成等号两边的键值对应关系,例如:

test=com.alibaba.dubbo.rpc.filter.TestFilter

loadFile的任务就是把test和解析过以后的TestFilter类关系对应上,供以后的getExtension查找使用。注意看其中的这几行代码:

...... clazz.getConstructor(type); //判断是否为wrapper实现Set
> wrappers = cachedWrapperClasses;if (wrappers == null) { cachedWrapperClasses = new ConcurrentHashSet
>(); wrappers = cachedWrapperClasses;}wrappers.add(clazz);......

这里就完成了cachedWrapperClasses的初始化,它根据查看配置文件中定义的扩展点实现是否包含一个带有当前类型的构造方法为条件,确定哪些是wrapper,这样我们就可以发现:

filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapperlistener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper

这两行命中了。这也是之后在真正获取protocol扩展点时会动态注入的两个重要包装类,前者完成拦截器,后者完成监听器。

转载于:https://my.oschina.net/oosc/blog/1791188

你可能感兴趣的文章
阿里架构师浅析体面编码之代码注释评论
查看>>
Java springcloud B2B2C o2o多用户商城 springcloud架构(四)SpringBoot 整合JPA
查看>>
教你如何自学UI设计
查看>>
单颗GPU计算能力太多、太贵?阿里云发布云上首个轻量级GPU实例
查看>>
Python数据库MongoDB骚操作
查看>>
Unity(创建脚本)
查看>>
Network组件
查看>>
FastDFS安装、配置、部署(一)
查看>>
记一次CentOS6.4 安装SVN
查看>>
我的友情链接
查看>>
我的友情链接
查看>>
redhat centos apache 403 错误 Forbidden You don't have permission to access / on this server
查看>>
5.PowerShell -- 数组和哈希表
查看>>
Forcing the Removal of a Domain Controller
查看>>
find命令、文件名后缀
查看>>
C 语言学习笔记
查看>>
redhat5.8日志文件远端存放
查看>>
我的友情链接
查看>>
华为网络规划
查看>>
网络整合营销(外贸篇)试读样章
查看>>