责任链设计模式在Dubbo中的应用深度解析

在介绍责任链设计模式在Dubbo中的应用之前,先来了解一下该设计模式。

责任链模式定义

这里引用菜鸟教程的定义

责任链模式通过将多个处理器(处理对象)以链式结构连接起来,使得请求沿着这条链传递,直到有一个处理器处理该请求为止。

责任链模式允许多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求。

责任链设计模式属于行为型模式

使用场景

  • 当有多个对象可以处理请求,且具体由哪个对象处理由运行时决定时。
  • 当需要向多个对象中的一个提交请求,而不想明确指定接收者时。

优缺点

优点

  1. 降低耦合度:发送者和接收者之间解耦。
  2. 简化对象:对象不需要知道链的结构。
  3. 灵活性:通过改变链的成员或顺序,动态地新增或删除责任。
  4. 易于扩展:增加新的请求处理类很方便。

缺点

  1. 请求未被处理:不能保证请求一定会被链中的某个处理者接收。
  2. 性能影响:可能影响系统性能,且调试困难,可能导致循环调用。
  3. 难以观察:运行时特征不明显,可能妨碍除错。

菜鸟教程的示例

具体代码可以到菜鸟教程看一下,这里不再赘述

www.runoob.com/design-patt...

以上定义均采于菜鸟教程,dubbo中的应用才是本篇的重点!

Dubbo中的应用

版本:3.2.6

构建责任链

首先我们来看下DefualtFilterChainBuilder#buildInokerChain()方法,此方法会为传入的Invoker构建一个Filter责任链,目的是在进行Invoker调用invoke时,能够去进行一系列的Filter操作,实现些扩展的功能。

java 复制代码
/**
 * build consumer/provider filter chain
 */
@Override
public <T> Invoker<T> buildInvokerChain(final Invoker<T> originalInvoker, String key, String group) {
    Invoker<T> last = originalInvoker;
    URL url = originalInvoker.getUrl();
    List<ModuleModel> moduleModels = getModuleModelsFromUrl(url);
    List<Filter> filters;
    if (moduleModels != null && moduleModels.size() == 1) {
        // 通过spi机制获取所有Filter的Activate扩展点
        filters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModels.get(0))
                .getActivateExtension(url, key, group);
    } else if (moduleModels != null && moduleModels.size() > 1) {
        filters = new ArrayList<>();
        List<ExtensionDirector> directors = new ArrayList<>();
        for (ModuleModel moduleModel : moduleModels) {
            List<Filter> tempFilters = ScopeModelUtil.getExtensionLoader(Filter.class, moduleModel)
                    .getActivateExtension(url, key, group);
            filters.addAll(tempFilters);
            directors.add(moduleModel.getExtensionDirector());
        }
        filters = sortingAndDeduplication(filters, directors);

    } else {
        filters = ScopeModelUtil.getExtensionLoader(Filter.class, null).getActivateExtension(url, key, group);
    }
    // 为每个Filter的Invoker设置next节点
    if (!CollectionUtils.isEmpty(filters)) {
        for (int i = filters.size() - 1; i >= 0; i--) {
            final Filter filter = filters.get(i);
            final Invoker<T> next = last;
            last = new CopyOfFilterChainNode<>(originalInvoker, next, filter);
        }
        return new CallbackRegistrationInvoker<>(last, filters);
    }

    return last;
}

责任链构建过程

一:传入原始Node,此处为originalInvoker

二:通过SPI扩展机制中的getActivateExtension获取所有Filter列表

三:将所有Filter循环,再循环中,每个Node里都有next节点,设置每个Nodenext节点,next节点和originalInvokerFilter共通构造一个新的Node

四:最后,将构建的最后一个Node作为last节点返回

之后,我们以consumer端服务调用为例,看一下在invoke时,FilterChain是如何生效的

通过调试可知,优先执行CallbackRegistrationInvoker下的invoke方法

java 复制代码
@Override
public Result invoke(Invocation invocation) throws RpcException {
    Result asyncResult = filterInvoker.invoke(invocation);
    // 。。。。。。
    return asyncResult;
}

此方法将之前构建InvokerChain时,得到的last,即最后一个节点,filterInvoker进行invoke调用

再往下,调用到CopyOfFilterChainNode类的invoke方法

java 复制代码
@Override
public Result invoke(Invocation invocation) throws RpcException {
    Result asyncResult;
    try {
        InvocationProfilerUtils.enterDetailProfiler(
                invocation, () -> "Filter " + filter.getClass().getName() + " invoke.");
        asyncResult = filter.invoke(nextNode, invocation);
        // ................此处源码省略
    return asyncResult;
}

发现此处会去调用BaseFilter的invoke方法

java 复制代码
/**
 * Always call invoker.invoke() in the implementation to hand over the request to the next filter node.
 */
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;

实现BaseFilter接口的类有很多,我们来举一个例子,通过调试,会发现先进入到ConsumerContextFilter,可以说,这个filter就是之前build出来的last节点,其中,我们看下忽略invoke中的业务层代码,只看最后的invoker.invoke方法

java 复制代码
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    // ........................
    return invoker.invoke(invocation);
}

完成调用后,会使用invoker去调用invoke,此时的invoker的类型是CopyOfFilterChainNode,因此每次调用完,都会回到前面的CopyOfFilterChainNodeinvoke方法,在这个方法中,又会继续向下传入nextNode,来让nextNode进行invoke调用,以此类推,直到最后一个originalInvoker执行完invoke之后结束。

总结

到此,dubboFilterChain的例子就结束了,其中,运用了责任链设计模式,其实就是先构建这个链路,将各个节点通过nextNode连接起来,然后使用lastNode去调用,每次调用时将下一个要调用的节点传入,依次执行,直到最后一个不包含nextNode的节点执行完毕,整个过程就结束了。

相关推荐
三金C_C2 小时前
单例模式解析
单例模式·设计模式·线程锁
ShareBeHappy_Qin4 小时前
设计模式——设计模式理念
java·设计模式
木子庆五6 小时前
Android设计模式之代理模式
android·设计模式·代理模式
前端_ID林8 小时前
前端必须知道的设计模式
设计模式
麦客奥德彪10 小时前
设计模式分类与应用指南
设计模式
小宋要上岸10 小时前
设计模式-单例模式
单例模式·设计模式
程序员JerrySUN11 小时前
设计模式 Day 1:单例模式(Singleton Pattern)详解
单例模式·设计模式
古力德13 小时前
代码重构之[过长参数列表]
设计模式·代码规范
OpenSeek15 小时前
【设计模式】面向对象的设计模式概述
设计模式·c#·设计原则
十五年专注C++开发16 小时前
设计模式之适配器模式(二):STL适配器
c++·设计模式·stl·适配器模式·包装器