dubbo的InvocationChain
个人觉得dubbo比较好的设计是:一个是Cooma微容器设计、另一个就是InvocationChain了
Cooma微容器是自己实现了一套SPI,方便了用户做扩展;
InvocationChain类似于servlet中的filter,在用户开发了扩展程序之后,能够方便的插入到consumer和provider的逻辑中
InvocationChain的构建
provider端InvocationChain构建:

具体看buildInvokerChain的实现,参数invoker就是被Wrapper的服务(com.xxx.HelloService)的实例,protocol是injvm; group=provider; key = service.filer
**流程 **
- 首先从扩展点获取所有激活并且作用在provider端的Filter,filter list是按照Filter上的注解order升序排列
- for循环是从filter list的末尾开始,filter[0]的next指向filter[1], list最末尾的filter[n-1] next指向了参数invoker。举例 filter list有4个元素,filter[0]->filter[1]->filter[2]->filter[3]->invoker
- 返回给最外面的匿名包装Invoker filter[0], 在调用invoker.invoke()的时候,就能从 filter[0]开始逐个filter访问一遍,实现了访问实例invoker之前的filter
private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) {
Invoker<T> last = invoker;
List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group);
if (filters.size() > 0) {
for (int i = filters.size() - 1; i >= 0; i --) {
final Filter filter = filters.get(i);
final Invoker<T> next = last;
last = new Invoker<T>() {
public Class<T> getInterface() {
return invoker.getInterface();
}
public URL getUrl() {
return invoker.getUrl();
}
public boolean isAvailable() {
return invoker.isAvailable();
}
public Result invoke(Invocation invocation) throws RpcException {
return filter.invoke(next, invocation);
}
public void destroy() {
invoker.destroy();
}
@Override
public String toString() {
return invoker.toString();
}
};
}
}
return last;
}
consumer端InvocationChain构建

consumer端buildInvokerChain流程一样的,只不过获取的所有group=consumer的filter。
总结
上面介绍了dubbo的InvocationChain的机制,我们可以想象用户自动一个provider或者consumer的filter是很简单的,只要增加一个Filter扩展点,指定排序order值就好了,dubbo会自己去主动加载。也不要把自定义的扩展点写在dubbo框架里面
有了Filter chain 用户想做dubbo调用自定义的监控和扩展就非常方便了,比如监控调用关系,调用链量,RT等等
一些关于Dubbo SPI解释
ExtensionLoader.getExtensionLoader(Protocol.class).getAdaptiveExtension()
我们知道加载protocol的SPI扩展点的时候,实际上是dubbo的SPI机制自动生成了一个Protocol$Adpative的类,它根据url里面的protocol字段自动加载SPI扩展点
import com.alibaba.dubbo.common.extension.ExtensionLoader;
public class Protocol$Adpative implements Protocol {
public Invoker refer(Class arg0, URL arg1) throws Class {
if (arg1 == null) throw new IllegalArgumentException("url == null");
URL url = arg1;
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(Protocol) name from url(" + url.toString() + ") use keys([protocol])");
Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
return extension.refer(arg0, arg1);
}
public Exporter export(Invoker arg0) throws Invoker {
if (arg0 == null) throw new IllegalArgumentException("Invoker argument == null");
if (arg0.getUrl() == null) throw new IllegalArgumentException("Invoker argument getUrl() == null");URL url = arg0.getUrl();
String extName = ( url.getProtocol() == null ? "dubbo" : url.getProtocol() );
if(extName == null) throw new IllegalStateException("Fail to get extension(Protocol) name from url(" + url.toString() + ") use keys([protocol])");
Protocol extension = (Protocol)ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName);
return extension.export(arg0);
}
public void destroy() {
throw new UnsupportedOperationException("method public abstract void Protocol.destroy() of interface Protocol is not adaptive method!");
}
public int getDefaultPort() {
throw new UnsupportedOperationException("method public abstract int Protocol.getDefaultPort() of interface Protocol is not adaptive method!");
}
}
然后在ExtensionLoader.getExtensionLoader(Protocol.class).getExtension(extName) 里面还有一些规则当Protocol有wrapper包装类的时候,返回的是包装类。
Protocol有2个包装类:ProtocolFilterWrapper和ProtocolListenerWrapper
private T createExtension(String name) {
Class<?> clazz = getExtensionClasses().get(name);
if (clazz == null) {
throw findException(name);
}
try {
T instance = (T) EXTENSION_INSTANCES.get(clazz);
if (instance == null) {
EXTENSION_INSTANCES.putIfAbsent(clazz, (T) clazz.newInstance());
instance = (T) EXTENSION_INSTANCES.get(clazz);
}
injectExtension(instance);
Set<Class<?>> wrapperClasses = cachedWrapperClasses;
if (wrapperClasses != null && wrapperClasses.size() > 0) {
for (Class<?> wrapperClass : wrapperClasses) {
instance = injectExtension((T) wrapperClass.getConstructor(type).newInstance(instance));
}
}
return instance;
} catch (Throwable t) {
throw new IllegalStateException("Extension instance(name: " + name + ", class: " +
type + ") could not be instantiated: " + t.getMessage(), t);
}
}
dubbo的InvocationChain的更多相关文章
- 用dubbo时遇到的一个序列化的坑
首先,这是标题党,问题并不是出现在序列化上,这是报错的一部分: Caused by: com.alibaba.dubbo.remoting.RemotingException: Failed to s ...
- dubbo服务提供与消费
一.前言 项目中用到了Dubbo,临时抱大腿,学习了dubbo的简单实用方法.现在就来总结一下dubbo如何提供服务,如何消费服务,并做了一个简单的demo作为参考. 二.Dubbo是什么 Dubbo ...
- 分布式学习系列【dubbo入门实践】
分布式学习系列[dubbo入门实践] dubbo架构 组成部分:provider,consumer,registry,monitor: provider,consumer注册,订阅类似于消息队列的注册 ...
- Maven多模块,Dubbo分布式服务框架,SpringMVC,前后端分离项目,基础搭建,搭建过程出现的问题
现互联网公司后端架构常用到Spring+SpringMVC+MyBatis,通过Maven来构建.通过学习,我已经掌握了基本的搭建过程,写下基础文章为而后的深入学习奠定基础. 首先说一下这篇文章的主要 ...
- Dubbo 备注
Dubbo是阿里开源的一款服务治理中间件,主要包含如下节点: Provider: 暴露服务的服务提供方. Consumer: 调用远程服务的服务消费方. Registry: 服务注册与发现的注册中心. ...
- Dubbo学习小记
前言 周一入职的新公司,到了公司第一件事自然是要熟悉新公司使用的各种技术,搭建本地的环境. 熟悉新公司技术的过程中,首先就是Maven,这个前面已经写过文章了,然后就是Dubbo----公司的服务都是 ...
- Running Dubbo On Spring Boot
Dubbo(http://dubbo.io/) 是阿里的开源的一款分布式服务框架.而Spring Boot则是Spring社区这两年致力于打造的简化Java配置的微服务框架. 利用他们各自优势,配置到 ...
- 【转】Dubbo使用例子并且和Spring集成使用
一.编写客户端和服务器端共用接口类1.登录接口类public interface LoginService { public User login(String name, String psw ...
- 基于SOA分布式架构的dubbo框架基础学习篇
以需求用例为基,抽象接口,Case&Coding两条线并行,服务(M)&消费(VC)分离,单元.接口.功能.集成四层质量管理,自动化集成.测试.交付全程支持. 3个大阶段(需求分析阶段 ...
随机推荐
- Myeclipse配置tomcat,以及简单的Myeclipse的配置
第一次总结技术相关的东西,那就坚持下去每天写一点.[有错欢迎指正,本人小白,轻虐] 首先,(以我的为例子吧)需要准备原材料,当然了也需要根据自己的机器底层架构选择了---Myeclipse(2015) ...
- Java最大公约数和最小公倍数的求法(辗转相除法)
这道题计算了三个数的最小公倍数 import java.util.Scanner; public class D { public static int gcd(int a,int b) { int ...
- Sharepoint对List增删改操作
在sharepoint的开发过程中,用得最多的,就是获取sharepoint的列表数据,以及对其进行一系列的增删改查等操作,这里主要是记录一些常用的操作,通过对象模型方式对数据进行增删改查. 由于sh ...
- 【Unity3D与23种设计模式】建造者模式(Builder)
GoF中定义: "将一个复杂的构建流程与它的对象表现分离出来,让相同的构建流程可以产生不同的对象行为表现." 建造者模式可以分为两个步骤来实施: 1.将复杂的构建流程独立出来,并将 ...
- Python快速入门之与C语言异同
代码较长,建议使用电脑阅读本文. 10分钟入门Python 本文中使用的是Python3如果你曾经学过C语言,阅读此文,相信你能迅速发现这两种语言的异同,达到快速入门的目的.下面将开始介绍它们的异同. ...
- 我的linux学习之路--(二)linux常用命令
1.date 时间管理 电脑主板有电池,所有电脑断电时间正确,rtc linux:rtc 硬件时钟 clock/hwclock 系统时钟(linux操作系统用软件模拟震荡器计算)date看到就是 命令 ...
- Mycat 配置说明(schema.xml )
Schema.xml 作为 MyCat中重要的配置文件之一,管理着 MyCat的逻辑库.表.分片规则.DataNode以 及DataSource.弄懂这些配置,是正确使用MyCat的前提. schem ...
- iOS CocoaPods一些特别的用法 指定版本、版本介绍、忽略警告
简介 介绍一些CocoaPods一些特别的用法 CocoaPods github地址 CocoaPods 官方地址 1. 指定第三方库版本 1. 固定版本 target 'MyApp' do use_ ...
- codeforce round#466(div.2) B. Our Tanya is Crying Out Loud
B. Our Tanya is Crying Out Loud time limit per test1 second memory limit per test256 megabytes input ...
- IDEA 中配置JDK
提前安装jdk,配置环境变量 一.配置jdk 1.依次点开File -->Project Structure,点击左侧标签页,点击SDKs 2.点击+号,选SDK 3.在弹出框选择jdk路径(我 ...