一个排序引发的BUG (上)

简介: 一个排序引发的BUG (上)

你好呀,我是why。

前两天在 Git 上闲逛的时候又不知不觉逛到 Dubbo 那里去了。

看了一下最近一个月的数据,社区活跃度还是很高的:

image.png


然后看了一下最新的 issue,大家提问都很积极。

其中看到了这样的一个 issue,发现有点意思:

https://github.com/apache/dubbo/issues/8055


image.png


于是写下这篇文章给你分享一下这个 BUG 和 BUG 背后的故事。

放心,就算你完全不懂 Dubbo,也不影响你了解这个 BUG。

先说一下,下文中提到的 Dubbo 代码,没有特别说明的地方,都是我从 git 上拉下来的 Master 分支上的代码


啥 BUG 啊?


先给你描述一个这个 BUG 是啥样的。

其实就是这个 issue 的作者写出来的:Dubbo 框架里面的 Filter 排序过程有问题,即使按照框架要求写好规则后,最终生成的 Filter 链并不是我们想要的。

那么完全不懂 Dubbo 的朋友可能就遇到了第一个问题:啥是 Filter 呢?

其实就是一个过滤器而已,和 web 服务里面过滤器在概念上没啥两样。而 Dubbo 有非常多的 Filter,这些 Filter 共同组成了一个 Filter 调用链。

引用官网上的一个调用链路图,在 Filter 的地方我框起来了:

image.png


可以看到 Filter 是 Dubbo 框架的一个非常核心的组成部分,很多很多的功能都是从 Filter 扩展出来的。

你要是还不明白也没关系,你只要知道有这样的一个 Filter 调用链就行了,链上的 Filter 各司其职,各干各的事儿。

好的,那么现在需求来了:

我现在要求链上的 Filter 的执行顺序是我能控制的,即我定义 Filter 的时候你得给我留个地方设置它的优先级。

听起来是很简单的一个需求,对吧?

我直接给你留个口子,让你输入 order 参数,不输入给个默认值,然后组装 Filter 链的时候根据 Order 排个序。

不是我吹牛,十分钟就能写完,中间还带着三分钟的摸鱼。

image.png


但是,就这么个需求出 BUG 了。

具体啥现象呢?

我这里把项目拉下来,基于官方的测试用例,改巴改巴,给你演示一下这个 BUG 的体现是啥。

在 Dubbo 里面有这样的一个注解:

org.apache.dubbo.common.extension.Activate


image.png

这里的 Order 就是做排序用的。简单演示一下,你看我现在有 5 个 Filter:


image.png


排序规则是 Order 越小的越先执行,那么这个 Filter 链的执行顺序应该是这样的:

Filter4 -> Filter3 -> Filter2 -> Filter1 -> Filter5

搞个测试案例,我们验证一下:

image.png

符合预期,没有任何毛病。

另外说明一下,官方的关于 Filter 的测试用例在这里,你有兴趣,源码拉下来就可以看:

org.apache.dubbo.common.extension.support.ActivateComparatorTest#testActivateComparator

不管是官方的案例,还是我自己写的案例,其中最关键的排序功能是这一行代码实现的:

Collections.sort(filters, ActivateComparator.COMPARATOR)

而这一行代码里面最关键的就是 ActivateComparator.COMPARATOR 这个东西。

这个东西就是 BUG 之源,不慌,等下再说。

那么为什么说它有 BUG 呢?

前面演示了正常的情况下,是符合预期的。

但是你看 Activate 注解,里面还有这样的两个东西:

image.png

before、after,含义是指定 Filter A 在 Filter B 之前或者之后执行。

但是被打上了 @Deprecated 注解,字段说明上也备注了:

Deprecated since 2.7.0

2.7.0 之后被废除。

那么就有点意思了,为啥被废除?

来,看个例子,还是刚刚的那个测试用例。

我就稍微的这么一改:

@Activate(before = "_2")
public class Filter5 implements Filter0{
}

改动点就是在 Filter5 上配置了:

@Activate(before = "_2")

含义就是 Filter5 在 “_2” 之前执行。

“_2” 是啥?

就是 Filter2 的一个映射而已:

image.png

那么问题就来了,作为一个正常的程序猿,自信的对 Filter5 进行了这个改动之后,他内心的想法一定是想要把这样的 Filter 链:

Filter4 -> Filter3 -> Filter2 -> Filter1 -> Filter5

修改为这样:(Filter5 在 Filter2 之前执行):

Filter4 -> Filter3 -> Filter5 -> Filter2 -> Filter1

那么实际情况是怎样的呢?

来跑一把:

image.png

咋回事?这不是我预期的执行链啊?

是的,这就是 BUG 的表现。


image.png

目录
相关文章
|
7月前
|
人工智能 自然语言处理 机器人
创新场景丨大模型时代,重塑智能终端新体验
大模型为智能终端带来的变革是全方位的,但挑战也同样显而易见。云侧部署的大模型加端侧应用的大模型是综合平衡性能、成本、功耗、隐私、速度之下的最佳选择。
293 0
|
6月前
|
存储 C++
UE5 C++:自定义Http节点获取Header数据
综上,通过为UE5创建一个自定义HTTP请求类并覆盖GetResult方法,就能成功地从HTTP响应的Header数据中提取信息。在项目中使用自定义类,不仅可以方便地访问响应头数据,也可随时使用这些信息。希望这种方法可以为你的开发过程带来便利和效益。
221 35
|
7月前
|
Java 程序员
菜鸟之路Day22一一反射与动态代理
本文介绍了Java反射机制和动态代理的基本概念及应用。反射允许编程访问类的成员变量、构造方法和成员方法,通过三种方式获取Class对象,并演示了如何使用反射创建对象、调用方法和修改字段值。动态代理则通过接口实现无侵入式功能增强,展示了如何利用`Proxy`类和`InvocationHandler`接口生成代理对象并拦截方法调用。结合实例代码,详细讲解了反射在实际开发中的应用场景,如保存对象信息到文件和根据配置文件动态创建对象。 反射的主要作用包括: 1. 获取类的所有信息。 2. 结合配置文件动态创建对象。 动态代理的核心优势在于能够在不修改原有代码的情况下,为对象添加额外功能。
112 0
|
Java 程序员 开发者
深入理解Java并发编程:线程同步与锁机制
【4月更文挑战第30天】 在多线程的世界中,确保数据的一致性和线程间的有效通信是至关重要的。本文将深入探讨Java并发编程中的核心概念——线程同步与锁机制。我们将从基本的synchronized关键字开始,逐步过渡到更复杂的ReentrantLock类,并探讨它们如何帮助我们在多线程环境中保持数据完整性和避免常见的并发问题。文章还将通过示例代码,展示这些同步工具在实际开发中的应用,帮助读者构建对Java并发编程深层次的理解。
|
存储 设计模式 前端开发
自定义MVC介绍
自定义MVC介绍
68 0
|
Linux 开发工具 Android开发
Docker系列(1)安装Linux系统编译Android源码
Docker系列(1)安装Linux系统编译Android源码
390 0
|
SQL 关系型数据库 分布式数据库
PolarDB常见问题之PolarDB的CPU跑高如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。
|
机器学习/深度学习
3 个进程 P1、P2、P3 互斥地使用一个包含 N(N > 0)个单元的缓冲区。P1 每次用 produce() 生成一个正整数,并用 put() 将其送入缓冲区的某一空单元中 ;P2每次用 get
3 个进程 P1、P2、P3 互斥地使用一个包含 N(N > 0)个单元的缓冲区。P1 每次用 produce() 生成一个正整数,并用 put() 将其送入缓冲区的某一空单元中 ;P2每次用 get
【中级软件设计师】—(针对上午题)浮点数(十三)
【中级软件设计师】—(针对上午题)浮点数(十三)