dubbo的拦截器和监听器

简介: dubbo的拦截器和监听器

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

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

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

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

按照这个调用流程,没错啊,可每一个环节都没有使用filterlistener属性的痕迹,有点抓瞎了啊。要说用好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

我们已经找到了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);
}

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

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

getExtension()  -->  createExtension()
                            |
                            +-->      ......
                                    Set<Class<?>> 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<Class<?>> wrappers = cachedWrapperClasses;
if (wrappers == null) {
    cachedWrapperClasses = new ConcurrentHashSet<Class<?>>();
    wrappers = cachedWrapperClasses;
}
wrappers.add(clazz);
......

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

filter=com.alibaba.dubbo.rpc.protocol.ProtocolFilterWrapper
listener=com.alibaba.dubbo.rpc.protocol.ProtocolListenerWrapper

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

至于拦截器和监听器的使用方法,我实在不知道除了官方提到的内容以外还有什么好补充的了,那就写到这里吧~

相关文章
|
4月前
|
Dubbo Java 应用服务中间件
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
微服务学习 | Springboot整合Dubbo+Nacos实现RPC调用
|
10月前
|
负载均衡 Dubbo 应用服务中间件
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
微服务技术系列教程(31) - Dubbo-原理及负载均衡分析
84 0
|
10月前
|
Dubbo Java 应用服务中间件
阿里新框架干掉微服务,换下Dubbo,Spring CloudAlibaba王者降临
tm快了,不知不觉中金九银十的秋招已经快结束了,不少同学现在已经拿到offer了吧~现在的面试可是越来越难了,动不动就是“互联网三高”。
阿里新框架干掉微服务,换下Dubbo,Spring CloudAlibaba王者降临
|
10月前
|
Dubbo Java 应用服务中间件
微服务技术系列教程(30) - Dubbo-SpringCloud与Dubbo区别
微服务技术系列教程(30) - Dubbo-SpringCloud与Dubbo区别
68 0
|
23天前
|
Dubbo Java 应用服务中间件
💥Spring Cloud Dubbo火爆来袭!微服务通信的终极利器,你知道它有多强大吗?🔥
【8月更文挑战第29天】随着信息技术的发展,微服务架构成为企业应用开发的主流模式,而高效的微服务通信至关重要。Spring Cloud Dubbo通过整合Dubbo与Spring Cloud的优势,提供高性能RPC通信及丰富的生态支持,包括服务注册与发现、负载均衡和容错机制等,简化了服务调用管理并支持多种通信协议,提升了系统的可伸缩性和稳定性,成为微服务通信领域的优选方案。开发者仅需关注业务逻辑,而无需过多关心底层通信细节,使得Spring Cloud Dubbo在未来微服务开发中将更加受到青睐。
49 0
|
1月前
|
负载均衡 Dubbo 应用服务中间件
框架巨擘:Dubbo如何一统异构微服务江湖,成为开发者的超级武器!
【8月更文挑战第8天】在软件开发中,微服务架构因灵活性和可扩展性备受欢迎。面对异构微服务的挑战,Apache Dubbo作为高性能Java RPC框架脱颖而出。它具备服务注册与发现、负载均衡及容错机制等核心特性,支持多种通信协议和序列化方式,能有效连接不同技术栈的微服务。Dubbo的插件化设计保证了面向未来的扩展性,使其成为构建稳定高效分布式系统的理想选择。
35 5
|
4月前
|
Dubbo Java 应用服务中间件
阿里巴巴资深架构师深度解析微服务架构设计之SpringCloud+Dubbo
软件架构是一个包含各种组织的系统组织,这些组件包括Web服务器,应用服务器,数据库,存储,通讯层),它们彼此或和环境存在关系。系统架构的目标是解决利益相关者的关注点。
|
4月前
|
Dubbo Cloud Native 应用服务中间件
【阿里云云原生专栏】云原生环境下的微服务治理:阿里云 Dubbo 与 Nacos 的深度整合
【5月更文挑战第25天】阿里云Dubbo和Nacos提供微服务治理的强大工具,整合后实现灵活高效的治理。Dubbo是高性能RPC框架,Nacos则负责服务发现和配置管理。整合示例显示,通过Nacos注册中心,服务能便捷注册发现,动态管理配置。简化部署,提升适应性,但也需注意服务稳定性和策略规划。这种整合为云原生环境的微服务架构带来强大支持,未来应用前景广阔。
262 2
|
4月前
|
Dubbo Java 应用服务中间件
Spring Cloud Dubbo: 微服务通信的高效解决方案
【4月更文挑战第28天】在微服务架构的发展中,服务间的高效通信至关重要。Spring Cloud Dubbo 提供了一种基于 RPC 的通信方式,使得服务间的调用就像本地方法调用一样简单。本篇博客将探讨 Spring Cloud Dubbo 的核心概念,并通过具体实例展示其在项目中的实战应用。
98 2
|
4月前
|
Cloud Native Dubbo 应用服务中间件
【Dubbo3技术专题】拥有新时代的通信协议,引领云原生迈向更高的舞台 | 解密Dubbo3是如何从微服务升华到云原生领域
【Dubbo3技术专题】拥有新时代的通信协议,引领云原生迈向更高的舞台 | 解密Dubbo3是如何从微服务升华到云原生领域
101 1