乐趣区

关于dubbo:Dubbo架构设计与源码解析三责任链模式

作者:周可强

一、责任链模式简介

1、责任链模式定义

责任链(Chain of Responsibility)模式的定义:为了防止申请发送者与多个申请解决者耦合在一起,于是将所有申请的解决者通过前一对象记住其下一个对象的援用而连成一条链;当有申请产生时,可将申请沿着这条链传递,直到有对象解决它为止。在责任链模式中,客户只须要将申请发送到责任链上即可,毋庸关怀申请的解决细节和申请的传递过程,申请会主动进行传递。所以责任链将申请的发送者和申请的解决者解耦了。

2、责任链特点

责任链模式是一种对象行为型模式,

其次要长处如下。

1). 升高了对象之间的耦合度。该模式使得一个对象毋庸晓得到底是哪一个对象解决其申请以及链的构造,发送者和接收者也毋庸领有对方的明确信息。

2). 加强了零碎的可扩展性。能够依据须要减少新的申请解决类,满足开闭准则。

3). 加强了给对象指派职责的灵活性。当工作流程发生变化,能够动静地扭转链内的成员或者调动它们的秩序,也可动静地新增或者删除责任。责任链简化了对象之间的连贯。每个对象只需放弃一个指向其后继者的援用,不需放弃其余所有解决者的援用,这防止了应用泛滥的 if 或者 if···else 语句。

4). 责任分担。每个类只须要解决本人该解决的工作,不该解决的传递给下一个对象实现,明确各类的责任范畴,合乎类的繁多职责准则。



其次要毛病如下。

1). 不能保障每个申请肯定被解决。因为一个申请没有明确的接收者,所以不能保障它肯定会被解决,该申请可能始终传到链的末端都得不到解决。

2). 对比拟长的职责链,申请的解决可能波及多个解决对象,零碎性能将受到肯定影响。

3). 职责链建设的合理性要靠客户端来保障,减少了客户端的复杂性,可能会因为职责链的谬误设置而导致系统出错,如可能会造成循环调用。

3、责任链结构图











二、Dubbo 中的责任链模式

1、过滤器日志

通过打印过滤器的日志,咱们能够看到在公布服务的过程中,会顺次通过 dubbo 的每个过滤器类,以此来保障服务的欠缺。





2、过滤器简图

dubbo 通过将每个过滤器类 filter 封装成 dubbo 的外围模型 invoker 进行组装,最终造成早晨的过滤器责任链 filterChain。





3、过滤器类图

Protocol 是外围模型 invoker 裸露和援用的主性能入口,采纳 SPI 的接口,他的两个办法 export 和 refer 别离对应 provider 和 consumer 端的服务性能,ProtocolFilterWapper 则是 Dubbo 的过滤器的次要实现类,通过重写的 export 和 refer 指向 buildInvokerChain 办法,在 buildInvokerChain 中进行责任链的获取与组装,在 extensionLoader 中通过 SPI 获取 Filter 的各实现类,并通过 ActivateComparator 进行排序,最终造成残缺的责任链。





三、Dubbo 中各 Filter 责任介绍

1、provider 用到的 filter





2、consumer 用到的 filter





四、源码探析

进入到外围类 ProtocolFilterWrapper 中,在实现类中 export 和 refer,都采纳雷同的结构责任链办法 buildInvokerChain,只是通过参数 group 进行辨别





在 buildInvokerChain 中,通过 getActivateExtension 获取过滤器数组,并在之后封装成外围模型 invoker 并组装成责任链

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);
        // 创立带 Filter 链的 Invoker 对象
        if (!filters.isEmpty()) {for (int i = filters.size() - 1; i >= 0; i--) {final Filter filter = filters.get(i);
                final Invoker<T> next = last;
                last = new Invoker<T>() {

                    @Override
                    public Class<T> getInterface() {return invoker.getInterface();
                    }

                    @Override
                    public URL getUrl() {return invoker.getUrl();
                    }

                    @Override
                    public boolean isAvailable() {return invoker.isAvailable();
                    }

                    @Override
                    public Result invoke(Invocation invocation) throws RpcException {return filter.invoke(next, invocation);
                    }

                    @Override
                    public void destroy() {invoker.destroy();
                    }

                    @Override
                    public String toString() {return invoker.toString();
                    }
                };
            }
        }
        System.out.println("group:" + group);
        for (Filter filter : filters) {System.out.println(filter.getClass());
        }
        return last;
    }

getActivateExtension 是次要的组装逻辑,他蕴含获取与排序等逻辑

首先进行判断是否采纳零碎默认的 Filter 过滤器,并对每一个零碎过滤器进行校验是否移除,而后对系统过滤器排序,再通过指定的参数,减少用户自定义的过滤器组装责任链


public List<T> getActivateExtension(URL url, String key, String group) {
        // 从 Dubbo URL 取得参数值
        String value = url.getParameter(key);
        // 取得合乎主动激活条件的拓展对象数组
        return getActivateExtension(url, value == null || value.length() == 0 ? null : Constants.COMMA_SPLIT_PATTERN.split(value), group);
    }
public List<T> getActivateExtension(URL url, String[] values, String group) {List<T> exts = new ArrayList<T>();
        // 所有用户本人配置的 filter 信息(有些 Filter 是默认激活的,有些是配置激活的,这里的 names 就指的配置激活的 filter 信息)List<String> names = values == null ? new ArrayList<String>(0) : Arrays.asList(values);
        // 解决主动激活的拓展对象们
        // 判断不存在配置 `"-name"`。例如,<dubbo:service filter="-default" />,代表移除所有默认过滤器。if (!names.contains(Constants.REMOVE_VALUE_PREFIX + Constants.DEFAULT_KEY)) {
            // 取得拓展实现类数组
            getExtensionClasses();
            // 循环
            for (Map.Entry<String, Activate> entry : cachedActivates.entrySet()) {
                //name 指的是 SPI 读取的配置文件的 key
                String name = entry.getKey();
                Activate activate = entry.getValue();
                if (isMatchGroup(group, activate.group())) { // 匹配分组
                    // 取得拓展对象
                    T ext = getExtension(name);
                    if (!names.contains(name) // 不蕴含在自定义配置里。如果蕴含,会在上面的代码解决。&& !names.contains(Constants.REMOVE_VALUE_PREFIX + name) // 判断是否配置移除。例如 <dubbo:service filter="-monitor" />,则 MonitorFilter 会被移除
                            && isActive(activate, url)) { // 判断是否激活
                        exts.add(ext);
                    }
                }
            }
            // 排序
            Collections.sort(exts, ActivateComparator.COMPARATOR);
        }
        // 解决自定义配置的拓展对象们。例如在 <dubbo:service filter="demo" />,代表须要退出 DemoFilter
        List<T> usrs = new ArrayList<T>();
        for (int i = 0; i < names.size(); i++) {String name = names.get(i);
            if (!name.startsWith(Constants.REMOVE_VALUE_PREFIX) && !names.contains(Constants.REMOVE_VALUE_PREFIX + name)) { // 判断非移除的
                // 将配置的自定义在主动激活的拓展对象们后面。例如,<dubbo:service filter="demo,default,demo2" />,则 DemoFilter 就会放在默认的过滤器后面。if (Constants.DEFAULT_KEY.equals(name)) {if (!usrs.isEmpty()) {exts.addAll(0, usrs);
                        usrs.clear();}
                } else {
                    // 取得拓展对象
                    T ext = getExtension(name);
                    usrs.add(ext);
                }
            }
        }
        // 增加到后果集
        if (!usrs.isEmpty()) {exts.addAll(usrs);
        }
        return exts;
    }

零碎默认的过滤器和 udf 过滤器进行辨别

以 ContextFilter 为例,零碎默认过滤器蕴含 Activate 注解,用于指定所属分组与排序权重,用户本人实现的过滤器则不能增加 Activate 注解通过公布时指定所需的过滤器







咱们看下具体的排序比拟办法,首先判断 Activate 注解是否指定 before 和 after 参数用来指定排序,若不存在则采纳 order 权重进行排序

ActivateComparator.class
public int compare(Object o1, Object o2) {
        // 根本排序
        if (o1 == null && o2 == null) {return 0;}
        if (o1 == null) {return -1;}
        if (o2 == null) {return 1;}
        if (o1.equals(o2)) {return 0;}

        Activate a1 = o1.getClass().getAnnotation(Activate.class);
        Activate a2 = o2.getClass().getAnnotation(Activate.class);

        // 应用注解的 `after` 和 `before` 属性,排序
        if ((a1.before().length > 0 || a1.after().length > 0 || a2.before().length > 0 || a2.after().length > 0) // (a1 或 a2) 存在 (`after` 或 `before`) 属性。&& o1.getClass().getInterfaces().length > 0 && o1.getClass().getInterfaces()[0].isAnnotationPresent(SPI.class)) { // 实现的接口,有 @SPI 注解。// 取得拓展加载器
            ExtensionLoader<?> extensionLoader = ExtensionLoader.getExtensionLoader(o1.getClass().getInterfaces()[0]);
            // 以 a1 的视角,进行一次比拟
            if (a1.before().length > 0 || a1.after().length > 0) {String n2 = extensionLoader.getExtensionName(o2.getClass());
                for (String before : a1.before()) {if (before.equals(n2)) {return -1;}
                }
                for (String after : a1.after()) {if (after.equals(n2)) {return 1;}
                }
            }
            // 以 a2 的视角,进行一次比拟。if (a2.before().length > 0 || a2.after().length > 0) {String n1 = extensionLoader.getExtensionName(o1.getClass());
                for (String before : a2.before()) {if (before.equals(n1)) {return 1;}
                }
                for (String after : a2.after()) {if (after.equals(n1)) {return -1;}
                }
            }
        }

        // 应用注解的 `order` 属性,排序。int n1 = a1 == null ? 0 : a1.order();
        int n2 = a2 == null ? 0 : a2.order();
        // never return 0 even if n1 equals n2, otherwise, o1 and o2 will override each other in collection like HashSet
        return n1 > n2 ? 1 : -1;
    }

总结:
责任链模式是设计模式中简略且常见的设计模式,可能咱们日常中也会常常利用责任链模式,dubbo 中的责任链模式将灵活性施展的很充沛,不论是从分组概念、通过注解指定排序的优先级、每个 filter 的是否移除 等,将每个 filter 做成了可插拔的,缩小对代码的侵入性,这点是十分值得咱们学习的。

退出移动版