dubbo自定义mysql拦截器_Dubbo 拦截器和监听器(转)

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

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

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

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

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

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

registry=com.alibaba.dubbo.registry.integration.RegistryProtocol

dubbo=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.MockProtocol

injvm=com.alibaba.dubbo.rpc.protocol.injvm.InjvmProtocol

rmi=com.alibaba.dubbo.rpc.protocol.rmi.RmiProtocol

hessian=com.alibaba.dubbo.rpc.protocol.hessian.HessianProtocol

com.alibaba.dubbo.rpc.protocol.http.HttpProtocol

com.alibaba.dubbo.rpc.protocol.webservice.WebServiceProtocol

thrift=com.alibaba.dubbo.rpc.protocol.thrift.ThriftProtocol

memcached=com.alibaba.dubbo.rpc.protocol.memcached.MemcachedProtocol

redis=com.alibaba.dubbo.rpc.protocol.redis.RedisProtocol

rest=com.alibaba.dubbo.rpc.protocol.rest.RestProtocol

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

在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);

}

乍一看,并没有感觉有什么蹊跷,不过在单步调试中就会出现”诡异”现象(由于该类是动态创建的,所以该方法并不会被单步到,所以为分析带来了一定的干扰),我们得再往回倒一下,之前在dubbo中SPI的基础中曾经分析过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?tdsourcetag=s_pctim_aiomsg

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值