Apache Dubbo dubbo-compatible 兼容模块解析:com.alibaba.dubbo 到 org.apache.dubbo 的平滑迁移
导读
Apache Dubbo 从 2.7.x 版本起将包名从 com.alibaba.dubbo 迁移到 org.apache.dubbo,这对既有代码意味着大规模的 import 变更。本仓库通过 dubbo-compatible 模块提供了一套 com.alibaba.dubbo 命名空间下的兼容(bridge)API,使旧代码可以在不做(或少做)改动的前提下继续运行。本文以 dubbo-compatible/README.md 为主体,结合模块内的桥接实现源码与测试用例,讲解:兼容模块覆盖了哪些常用 API、这些 API 是如何"桥接"到新包名的、哪些 API 有单元测试保障、以及官方给出的迁移建议与边界。
一、背景:包名迁移与兼容模块的定位
dubbo-compatible/README.md 开篇说明了该模块存在的原因:
From 2.7.x,
Dubbohas renamed package toorg.apache.dubbo, sodubbo-compatiblemodule is provided.
也就是说,Dubbo 捐赠给 Apache 基金会后,2.7.x 将核心包从 com.alibaba.dubbo 重命名为 org.apache.dubbo。对于已经深度依赖旧包名的项目,一次性全量替换 import 风险较高,因此官方提供了 dubbo-compatible 模块,在其中"复刻"了最常用的旧 API(类/接口),供旧版本代码继续编译与运行。
需要注意的关键边界(同样来自 README,必须牢记):
- 有单元测试保障的只是一部分"最常用"的 API——README 明确列出了一份清单(见第二节);
- 清单之外的 bridge API 没有任何单元测试,README 原文提示 "they may work with wrong"(可能行为不正确);
- 官方建议新代码使用新 API 实现扩展(README 标注为 RECOMMENDED),并明确声明 "We will remove this module some day"——兼容模块是临时性的过渡工具,未来会被移除。
二、有单元测试保障的常用 API 清单
README 列出的"most popular APIs"共三组,全部可以在 dubbo-compatible/src/main/java/com/alibaba/dubbo 下找到对应源码文件:
| 旧包 API | 仓库中对应源码 |
|---|---|
com.alibaba.dubbo.rpc.Filter |
Filter.java |
com.alibaba.dubbo.rpc.Invocation |
Invocation.java |
com.alibaba.dubbo.rpc.Invoker |
Invoker.java |
com.alibaba.dubbo.rpc.Result |
Result.java |
com.alibaba.dubbo.rpc.RpcContext |
RpcContext.java |
com.alibaba.dubbo.rpc.RpcException |
RpcException.java |
com.alibaba.dubbo.config.annotation.Reference / Service |
Reference.java / Service.java |
com.alibaba.dubbo.config.spring.context.annotation.EnableDubbo |
EnableDubbo.java |
com.alibaba.dubbo.common.Constants / URL |
Constants.java / URL.java |
com.alibaba.dubbo.common.extension.ExtensionFactory |
ExtensionFactory.java |
com.alibaba.dubbo.common.serialize.Serialization / ObjectInput / ObjectOutput |
serialize 目录 |
com.alibaba.dubbo.rpc.service.EchoService / GenericService |
rpc/service 目录 |
README 还提到 com.alibaba.dubbo.cache.CacheFactory / Cache。此外,从源码结构看,模块内实际提供的兼容类远不止上表——com.alibaba.dubbo 下还包含 config(ApplicationConfig、ReferenceConfig、ServiceConfig、RegistryConfig 等)、registry(Registry、RegistryFactory)、remoting(Channel、Codec、Transporter 等)、rpc.cluster(Cluster、Router、LoadBalance 等)、container.page(QoS 控制台页面)等桥接类。但按 README 的定义,这些额外类属于"无单元测试的 bridge API",行为正确性没有保障,应优先迁移到新 API。
上述核心 API 的单元测试位于测试根目录 src/test/java/org/apache/dubbo 下,README 所称 "The above APIs work fine with some unit tests in the test root" 可对照这些测试验证:
- FilterTest.java:Filter 桥接行为(异常透传、默认方法调用、recreate)
- SerializationTest.java:Serialization 桥接
- EnableDubboTest.java、EnableDubboConfigTest.java:
@EnableDubbo注解驱动 - EchoServiceTest.java、GenericServiceTest.java:
EchoService/GenericService - RpcContextTest.java:
RpcContext - RouterTest.java:Router 新旧混用的加载
- ExtensionTest.java、ActivateComparatorTest.java:扩展加载与
@Activate排序(其中OldFilter0/OldFilter5等类专门模拟了旧包名的扩展实现)
三、桥接机制源码解析:旧 API 如何落到新实现
3.1 接口继承是桥接的第一层
以最常用的 Filter 为例(Filter.java):
@Deprecated
public interface Filter extends org.apache.dubbo.rpc.Filter {
Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException;
@Override
default org.apache.dubbo.rpc.Result invoke(
org.apache.dubbo.rpc.Invoker<?> invoker, org.apache.dubbo.rpc.Invocation invocation)
throws org.apache.dubbo.rpc.RpcException {
Result invokeResult =
invoke(new Invoker.CompatibleInvoker<>(invoker),
new Invocation.CompatibleInvocation(invocation));
if (invokeResult instanceof Result.CompatibleResult) {
return ((Result.CompatibleResult) invokeResult).getDelegate();
}
// 否则把旧 Result 的 value/exception/attachments 搬到 AsyncRpcResult 上
AsyncRpcResult asyncRpcResult = AsyncRpcResult.newDefaultAsyncResult(invocation);
...
return asyncRpcResult;
}
}
这里的设计可以概括为三层:
- 继承新接口:旧
Filter直接extends org.apache.dubbo.rpc.Filter,因此旧 Filter 的 SPI 实现(如META-INF/dubbo/下注册的com.alibaba.dubbo.rpc.Filter扩展)能被新框架的扩展加载器直接当作org.apache.dubbo.rpc.Filter使用; - default 方法做方向翻译:新框架调用的是
org.apache.dubbo.rpc.Invoker/Invocation参数的invoke。兼容接口的 default 实现把这些"新对象"包装成CompatibleInvoker/CompatibleInvocation,再回调用户只实现了"旧签名"invoke(Invoker, Invocation)的扩展逻辑; - 结果反向解包:如果旧实现返回
Result.CompatibleResult(内部持有 delegate),直接取getDelegate()还原出新Result;否则用AsyncRpcResult把 value、exception、attachments 逐项搬过去。
@Deprecated 注解明确表达了"旧 API 仅用于过渡"的定位。同样的模式贯穿整个模块:Invocation extends org.apache.dubbo.rpc.Invocation、Invoker<T> extends org.apache.dubbo.rpc.Invoker<T>、Result extends org.apache.dubbo.rpc.Result(见 Result.java)、ExtensionFactory extends org.apache.dubbo.common.extension.ExtensionFactory、Serialization extends org.apache.dubbo.common.serialize.Serialization 等,ExtensionFactory.java 和 Serialization.java 都是纯继承、零额外方法的"标记式"桥接。
3.2 CompatibleInvoker:包装新 Invoker 适配旧签名
Invoker.java 中的内部类 CompatibleInvoker<T> 是桥接的核心组件,其关键行为:
invoke(Invocation)时先判断被包装的新 invoker 本身是否恰好也是旧Invoker接口(即"旧实现"):- 是:直接调用旧的
invoke(Invocation),并把旧Result包成Result.CompatibleResult(必要时先用AsyncRpcResult搬运 value/exception/objectAttachments); - 不是:调用新 invoker 的
invoke(invocation.getOriginal()),再用CompatibleResult包住返回;
- 是:直接调用旧的
getUrl()返回new DelegateURL(invoker.getUrl()),即把新的org.apache.dubbo.common.URL包装成旧的com.alibaba.dubbo.common.URL;- 覆盖
hashCode()/equals()委托给内部 invoker,保证包装前后在集合、比较中的行为一致。
3.3 DelegateURL:URL 的双向委托
DelegateURL.java 是 com.alibaba.dubbo.common.URL 的委托子类:
@Deprecated
public class DelegateURL extends com.alibaba.dubbo.common.URL {
protected final org.apache.dubbo.common.URL apacheUrl;
public DelegateURL(org.apache.dubbo.common.URL apacheUrl) {
this.apacheUrl = apacheUrl;
}
@Override
public String getProtocol() {
return apacheUrl.getProtocol();
}
// 其余 get/set 方法同样逐项委托给 apacheUrl
}
它把 getProtocol()、setProtocol()、getUsername() 等每个方法逐一委托给内部的 org.apache.dubbo.common.URL,并提供静态工厂 DelegateURL.valueOf(String) 一步构造。这样,持有旧 com.alibaba.dubbo.common.URL 类型的旧代码拿到的 URL 数据,实际全部来自新 URL 对象,避免了两个 URL 模型之间的数据拷贝与漂移。
3.4 测试用例如何验证桥接
FilterTest.java 用同一份旧包 MyFilter 验证了两个方向的调用:
testDefault:以新org.apache.dubbo.rpc.Invocation(RpcInvocation)调用旧 Filter,走 default 桥接方法,断言res.recreate()得到"alibaba";testRecreate:走另一条 recreate 路径,断言"123test";testInvokeException:以旧LegacyInvocation调用,验证旧实现抛出的RpcException("arg0 illegal")能原样透传给调用方。
RouterTest.java 则验证了新旧 Router 扩展(CompatibleRouter、CompatibleRouter2、NewRouter)在扩展加载器中混用的正确性。这些测试就是 README 所说"上面那些 API work fine"的证据所在。
四、兼容注解 API:@Service、@Reference 与 @EnableDubbo
4.1 @Service:属性与新 @DubboService 对齐
旧的 Service.java 注解标有 @Deprecated,javadoc 中 @see DubboService 明确推荐使用新注解替代。其属性集与新 API 保持一致,常用的如:
@Deprecated
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Inherited
public @interface Service {
Class<?> interfaceClass() default void.class;
String interfaceName() default "";
String version() default "";
String group() default "";
String path() default "";
boolean export() default false;
boolean dynamic() default true;
String cluster() default "";
int timeout() default -1;
int retries() default -1;
String loadbalance() default "";
boolean async() default false;
int weight() default -1;
String mock() default "";
String[] filter() default {};
// 完整属性见源码
}
注意其中 application() 属性本身又被 @Deprecated 标注并提示 "Do not set it and use the global Application Config"(Service.java),这一点与新版注解的处理一致。
4.2 @EnableDubbo:元注解组合
EnableDubbo.java 的桥接方式与接口类不同——它不继承任何东西,而是作为元注解组合直接复用新框架的实现:
@Deprecated
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
@EnableDubboConfig
@DubboComponentScan
public @interface EnableDubbo {
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
@AliasFor(annotation = DubboComponentScan.class, attribute = "basePackageClasses")
Class<?>[] scanBasePackageClasses() default {};
@AliasFor(annotation = EnableDubboConfig.class, attribute = "multiple")
boolean multipleConfig() default false;
}
即在旧注解上叠加新的 @EnableDubboConfig 与 @DubboComponentScan,并用 Spring 的 @AliasFor 把旧属性 scanBasePackages / scanBasePackageClasses / multipleConfig 映射到 org.apache.dubbo 包下对应注解的属性。旧代码写 @EnableDubbo(scanBasePackages = "com.example") 后,Spring 容器内实际生效的是新版 DubboComponentScan 的扫描逻辑。相关验证见 EnableDubboTest.java 与 EnableDubboConfigTest.java,测试工程内的 ProviderConfiguration.java、ConsumerConfiguration.java 则演示了新旧注解驱动下 provider/consumer 的实际配置。
五、模块依赖结构:兼容模块依赖什么
dubbo-compatible/pom.xml 说明了该模块在整体工程中的位置:
- 编译期依赖:
dubbo-config-spring(注解/Spring 集成能力的来源,@EnableDubbo桥接所依赖)、dubbo-qos(QoS 控制台命令桥接)、dubbo-remoting-zookeeper-curator5(注册中心)、dubbo-filter-cache与dubbo-filter-validation(缓存/校验 Filter 扩展),以及provided作用域的javax.servlet-api、javax.ws.rs-api(支撑container.page下的页面桥接类); - 测试期依赖:
dubbo-serialization-hessian2、dubbo-serialization-fastjson2、dubbo-registry-multicast、dubbo-registry-zookeeper、dubbo-configcenter-zookeeper、dubbo-metadata-report-zookeeper、com.alibaba:fastjson等,覆盖第二节所列单元测试所需的 SPI 实现; - 父工程为根 pom.xml 中的
org.apache.dubbo:dubbo-parent,随整个仓库一起构建。
六、使用建议与迁移路线
综合 README 与源码证据,使用该模块时的实践要点:
- 仅依赖有测试覆盖的 API 清单(第二节的表)。清单外的 bridge 类(如
remoting、container.page下的部分类)从源码结构看只是继承/委托的骨架,README 明确其"may work with wrong",生产代码不要依赖; - 旧扩展实现可平滑运行:如果你的自定义
Filter/Router/Serialization等扩展仍实现com.alibaba.dubbo旧接口(并注册在META-INF/dubbo/...SPI 文件中),由于兼容接口继承自新接口,SPI 加载器可直接发现它们——RouterTest.java 与 ExtensionTest.java 验证了新旧扩展混载的场景; - 新扩展一律用新 API 实现:README 将 "Implement your own extensions with new APIs" 标注为 RECOMMENDED。若确有旧 API 缺失或行为异常,官方给出的三条路是:用新 API 自行实现(推荐)、参照 Filter.java 的桥接方式补全兼容实现并向社区贡献、或在 GitHub 提交 issue;
- 规划迁移窗口:所有旧 API 均带
@Deprecated,且 README 声明该模块"some day"会被移除。合理的路线是:先接入dubbo-compatible保证旧代码可运行 → 逐步把 import 与注解(@Service/@Reference→@DubboService/@DubboReference,@EnableDubbo→@EnableDubboConfig/@DubboComponentScan)切换到org.apache.dubbo包 → 移除dubbo-compatible依赖。
小结
dubbo-compatible 是 Apache Dubbo 2.7.x 包名迁移期的"减震器":它通过**接口继承 + default 方法翻译 + Compatible 包装类(CompatibleInvoker/CompatibleResult/DelegateURL)**三层机制,让 com.alibaba.dubbo 命名空间下的 Filter、Invoker、Invocation、Result、RpcContext、注解与 URL 等常用 API 无缝落到 org.apache.dubbo 的新实现上。它是有明确边界的过渡设施——README 划定的测试覆盖清单可以放心使用,清单外的 bridge API 应视为不保证行为正确;而所有带 @Deprecated 的旧 API 都只是通往新包名的临时通道,新扩展实现应直接基于 org.apache.dubbo API 编写。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00