DBeaver 源码工程指南:基于 OSGi/Tycho 的构建体系、代码规范与协作约定详解
DBeaver 是一个用 Java 21 编写的免费开源跨平台数据库管理工具,支持 100+ 数据库驱动(以 JDBC 为主),构建于 Eclipse RCP 之上的 OSGi 插件架构。仓库根目录的 AGENTS.md 是一份面向 AI Agent 与人类贡献者的工程说明文档,系统定义了 DBeaver 社区版(CE)的仓库布局、Maven + Tycho 构建流程、单元测试运行方式、插件打包规则、编码/日志/异常/NLS 等代码规范,以及 Git 分支与 PR 协作约定。读完本文,你将能够独立理解 DBeaver 的多仓库聚合构建机制、P2 依赖解析原理,并遵循其既有约定对 OSGi 插件进行阅读、构建与合规修改。
一、项目定位与仓库布局
DBeaver CE 与商业产品共享同一套模型层:浏览器端对应仓库为 cloudbeaver,命令行工具对应仓库为 dbvr(这两个仓库均不在本仓库内)。本仓库内部由四部分构成:
| 目录 | 职责 | 对应文件形态 |
|---|---|---|
plugins/ |
主源码,全部为 OSGi bundle(插件) | 每个插件含 META-INF/MANIFEST.MF、plugin.xml、src/、pom.xml |
test/ |
测试插件,与生产插件一一镜像 | 如 PostgreSQL 测试插件 对应 plugins/org.jkiss.dbeaver.ext.postgresql |
features/ |
Eclipse feature 描述符 | 如 org.jkiss.dbeaver.ce.feature |
product/ |
Eclipse product 配置与聚合构建入口 | 如 community product |
从仓库结构看,plugins/ 下既有核心模块(org.jkiss.dbeaver.model、org.jkiss.dbeaver.model.sql、org.jkiss.dbeaver.registry 等),也有按数据库厂商划分的驱动扩展(ext.postgresql、ext.mysql、ext.oracle、ext.duckdb 等),每个厂商通常成对出现"模型插件 + UI 插件"(.ui 后缀)。
技术栈总览(与 AGENTS.md 的 Codebase 章节一致):
- 语言:Java 21(目标平台
JavaSE-21,禁止使用 preview 特性); - 平台:OSGi / Eclipse Equinox;
- UI:Eclipse RCP(SWT + JFace);
- 数据库连接:JDBC 或自研实现(如 WMI);
- SQL 解析:JSQLParser、ANTLR4(LSM 模块);
- 测试:JUnit 5、Mockito、自研 OSGi 测试运行器(
org.jkiss.dbeaver.osgi.test.runner)。
二、Maven + Tycho 构建体系
2.1 为什么不能单独构建一个插件
AGENTS.md 明确指出:在单个 bundle 目录里直接执行 mvn package 通常都会失败。原因在于 OSGi 目标平台解析:Tycho 编译一个 bundle 时,需要目标平台中包含它 Require-Bundle 声明的全部依赖,而这些依赖来自 Eclipse P2 仓库(见下文 2.3),单 bundle 构建时 Tycho 无法独立完成整个目标平台的收集。
2.2 全量产品构建命令
正确的做法是从聚合 POM 发起整仓构建:
# 完整产品构建(桌面版 CE + Eclipse 插件版 CE)
mvn package -f product/aggregate/pom.xml -T1C -Pproduct-dbeaver-ce,product-dbeaver-eclipse-ce
其中 -T1C 表示每个 CPU 核心一个线程的并行构建。product/aggregate/pom.xml 是关键的聚合入口,它将两个仓库挂入同一反应堆:
<modules>
<!-- dbeaver common -->
<module>../../../dbeaver-common</module>
<!-- dbeaver ce -->
<module>../..</module>
</modules>
即聚合 POM 同时纳入了本仓库(../..)和同级的 dbeaver-common 仓库。本仓库根 pom.xml 的 <parent> 正是 com.dbeaver.common.main(<relativePath>../dbeaver-common/pom.xml</relativePath>),Tycho 相关插件(target-platform-configuration、tycho-maven-plugin、tycho-compiler-plugin)也在此统一声明,并配置了 win32/linux/macosx 六种 OS/架构组合的环境矩阵。
此外,根 pom 中定义了一个默认激活的 desktop profile(当未设置 headless-platform 属性时激活),它把 test/ 模块纳入构建——这正是"没有独立测试命令"这一约定(2.4 节)的来源。
2.3 OSGi 依赖全部来自 P2,而非 Maven
这是理解 DBeaver 构建的关键:
- 所有 OSGi 依赖来自 Eclipse P2 仓库(不是 Maven),声明在各
layout=p2的根 POM 中; - 包括标准 Eclipse P2(RCP 开发基线)+ DBeaver 自维护 P2 仓库(配置项
repo.p2.eclipse.url); - 自维护 P2 的源码仓库是
dbeaver-deps-ce,它的作用是把传统 Maven 依赖转换成 P2 bundle(这样 SLF4J、JGit、Ant 等普通 Java 库才能以 OSGi 形式被 Require); - bundle 之间的依赖不写在
pom.xml里,而是写在MANIFEST.MF的Require-Bundle头中。
以 DuckDB 驱动插件的清单 为例,可以直观看到这种声明方式:
Bundle-SymbolicName: org.jkiss.dbeaver.ext.duckdb;singleton:=true
Require-Bundle: org.jkiss.dbeaver.model,
org.jkiss.dbeaver.model.sql,
org.jkiss.dbeaver.ext.generic,
org.jkiss.dbeaver.data.gis
Import-Package: org.jkiss.code,
org.jkiss.dbeaver.model.sql.format
Bundle-RequiredExecutionEnvironment: JavaSE-21
其中 Require-Bundle 列出 bundle 级依赖,Import-Package 列出包级依赖(org.jkiss.code 注解来自 dbeaver-common 提供的包),Bundle-RequiredExecutionEnvironment: JavaSE-21 印证了"必须 Java 21"的约束。
2.4 运行单元测试
由于 OSGi 测试要求构建环境中包含全部 bundle(或已安装到本地 .m2),在单个 bundle 内跑测试通常同样会失败。官方做法是整仓 verify:
mvn verify -f product/aggregate/pom.xml -T1C -Pproduct-dbeaver-ce,product-dbeaver-eclipse-ce
这会执行桌面 DBeaver CE 和 Eclipse 插件的测试。测试由 Maven Tycho 作为标准构建流程的一部分运行,不存在单独的 test-only Maven 命令——测试在 mvn install 或 mvn verify(配合 desktop 场景)时自动执行。
2.5 多仓库协同:project.deps 机制
AGENTS.md 规定了一套仓库间依赖管理约定:
- DBeaver 相关仓库位于同一组织(dbeaver)下;
- 每个仓库根目录可能有
project.deps文件,纯文本,每行写一个本仓库所依赖的仓库短名;本仓库的 project.deps 只有一行:dbeaver-common; - 所有 GitHub 仓库必须克隆到同一个父目录(文档称之为
DBEAVER_DEV_HOME,即本仓库的上一级目录)——这与 2.2 节聚合 POM 中../../../dbeaver-common的相对路径正好呼应; - 若依赖仓库在磁盘上缺失,AI Agent 可以自行将其克隆到
DBEAVER_DEV_HOME。
三、插件打包规则与许可头
3.1 一个合法插件的四要素
按 AGENTS.md 的 Plugin packaging rules,每个插件必须具备:
META-INF/MANIFEST.MF:OSGi bundle 元数据(SymbolicName、版本、Require-Bundle、Export-Package 等);pom.xml:packaging为eclipse-plugin;测试插件为eclipse-test-plugin;plugin.xml:声明 Eclipse 扩展点与扩展;src源码目录,路径在build.properties中指定(Tycho 的硬性要求)。
3.2 Apache 2.0 许可头
所有 OSS 仓库的每个 Java 文件都必须以 Apache 2.0 许可头开始,模板见 docs/license_header.txt:
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-${current-year} DBeaver Corp and others
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* ...
*/
注意两条规则:${current-year} 必须替换为当年年份;且修改任何既有 Java 文件时,必须同步把其中的年份更新为当前年份。
四、编码规范:注解、导入、硬编码与日志
4.1 注解约定
| 注解 | 来源 | 用法 |
|---|---|---|
@NotNull / @Nullable |
org.jkiss.code |
尽量用于所有方法参数与返回值 |
@Property |
org.jkiss.dbeaver.model.meta |
加在 getter 方法上,将对象属性暴露给 UI |
@Association |
模型元数据 | 标记关联集合(子集合) |
@ForTest |
项目内部 | 标记仅为单位测试访问而存在的成员 |
关于 @Property 有一个明确的坑(Common Pitfalls 章节):该注解在运行时通过反射处理,只能放在 getter 方法上,不能放在字段上。从源码看,Property.java 的声明印证了这一点:
@Target(value = {ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Property
{
String DEFAULT_LOCAL_STRING = "#"; //NON-NLS-1
...
ElementType.METHOD 的 @Target 约束意味着放在字段上会直接编译失败。
4.2 导入(import)规则
- Java 包的 import 必须按字母序排列;
- SDK import 与其他 import 之间用一个空行分隔,并放在 import 区块末尾;
- 代码修改/重构后,不再使用的 import 必须删除。
4.3 禁止硬编码
- 不硬编码常量:使用库中声明的常量、DBeaver 代码库中既有的
*Constants类,或按需新建; - 不硬编码 UI 文案:使用 NLS 的
*Messages资源包(详见 4.5);但异常消息必须用英文书写。
4.4 日志:统一使用 org.jkiss.dbeaver.Log
项目要求使用 Log.java(位于 org.jkiss.dbeaver.model 插件中)作为唯一日志门面,禁止 System.out 或其他日志体系(除非被直接要求)。
4.5 NLS / 本地化
每个含用户可见字符串的插件都有一对 *Messages.java + *Messages.properties(以及各语言变体),代码中通过 *Messages.MY_STRING_KEY 形式引用;plugin.xml 则使用 %key 语法引用 plugin.properties。新增任何文本常量时,至少补充英文本地化。仓库中此类文件随处可见,例如 UIConnectionMessages.properties、CubridMessages.properties 等,可对照参考其命名与键值组织方式。
五、异常处理与长时任务
5.1 DBException 是标准检查异常
DBException及其子类是数据库错误的标准检查异常(checked exception);- 向更上层暴露时,应将
SQLException及其他第三方库异常包装为DBException; - 非检查的运行时异常只在"别无选择"的罕见情况下使用。
5.2 长时任务与异步
- 长耗时方法应将
DBRProgressMonitor monitor作为第一个参数; - 异步任务使用 Jobs(通常继承
AbstractJob类)或RuntimeUtils等工具。
从源码看,AbstractJob.java 声明为 public abstract class AbstractJob extends Job(继承 Eclipse 的 org.eclipse.core.runtime.Job),与文档描述一致。
5.3 UI 线程安全(高频踩坑点)
所有 SWT/UI 更新必须运行在 display 线程上;跨线程时调用 UIUtils.asyncExec(Runnable)。该工具类位于 UIUtils.java(org.jkiss.dbeaver.ui 插件)。
六、单元测试编写规范
AGENTS.md 对测试的要求:
- 凡模型层(非 UI)函数,尽可能都应有单元测试;
- 测试插件放在
test/目录,且与生产插件镜像命名,如test/org.jkiss.dbeaver.ext.postgresql.test/对应plugins/org.jkiss.dbeaver.ext.postgresql/;仓库现有测试覆盖 PostgreSQL、MySQL、Oracle、Snowflake、ClickHouse、Greenplum、HANA、SQLite 等驱动(见 test 目录)。 - 测试类继承
DBeaverUnitTest(来自org.jkiss.dbeaver.osgi.test.runner),或针对需要运行中 OSGi 容器的集成测试使用@RunWithApplication/@RunWithProduct注解; - 测试随 Maven Tycho 构建执行(见 2.4 节),无独立测试命令。
自研 OSGi 测试运行器位于 plugins/org.jkiss.dbeaver.osgi.test.runner,从源码结构看,其提供了 OSGITestExtension(JUnit 5 扩展)、TestLauncher 测试启动器,以及 RunWithProduct.java、RunWithApplication.java 两个注解,与文档描述完全对应。
七、Git 分支与协作约定
AGENTS.md 的 Branches and Git Workflow 章节规定:
devel是主开发分支,所有 PR 必须指向该分支;- 发布分支命名
release_VERSION,每个版本一个,严禁直接提交; - 仅修错别字、格式或琐碎重构的 PR 通常不被接受(依据贡献者指南);
- 命名规范:issue、commit 消息、PR 标题均遵循
dbeaver/repo#issueNumber title格式,例如dbeaver/dbeaver#12345 Fix NPE in PostgreSQL dialect; - 分支命名:
dbeaver/repo#issueNumber-issueTitle,例如dbeaver/dbeaver#12345-fix-npe-postgresql; - PR 关联 issue:在 PR 描述中写
Closes org/project#issueNumber,例如Closes dbeaver/dbeaver#12345; - AI 贡献要求:AI 辅助的贡献应保持聚焦和小粒度,且每处改动须由人类贡献者理解并审查;若使用了 AI 工具生成代码,必须在 PR 描述中披露(例如:"This PR was generated with AI (GitHub Copilot)")。
详细的贡献流程以仓库外部的官方 Code contribution guide 为准(AGENTS.md 末尾给出的外链指向其 wiki,此处不重复)。
八、进阶文档索引
AGENTS.md 在 "Specific instruction" 一节中链接了两份深入文档,二者与本仓库根目录文件一一对应:
- DBeaver 架构(面向新功能设计与重构):涉及跨插件改动、模型层扩展设计时应先读;
- 新增数据库驱动指南:添加新数据库支持时的标准步骤,可结合 ext.duckdb 等小型驱动插件作为模板阅读。
九、常见坑点速查表
| 坑点 | 说明 | 依据 |
|---|---|---|
| UI 线程安全 | SWT/UI 更新必须在 display 线程,跨线程用 UIUtils.asyncExec |
AGENTS.md;UIUtils.java |
@Property 只能放 getter |
运行时反射处理,放字段无效 | Property.java |
| 必须 Java 21 | 目标平台 JavaSE-21,禁用 preview 特性 |
MANIFEST.MF 中 Bundle-RequiredExecutionEnvironment |
| 单 bundle 构建/测试必挂 | OSGi 需要全量 bundle 参与目标平台解析,须走聚合 POM | product/aggregate/pom.xml;pom.xml |
| 依赖不走 Maven | OSGi 依赖来自 P2,bundle 依赖写在 Require-Bundle 而非 pom |
各插件 MANIFEST.MF |
| 改文件忘改年份 | 修改 Java 文件须同步更新许可头年份 | docs/license_header.txt |
| 多仓库同目录 | 所有 dbeaver 仓库须克隆到同一 DBEAVER_DEV_HOME 父目录 |
project.deps;AGENTS.md |
适用前提说明:以上构建命令基于当前仓库的多仓库布局(dbeaver-common 位于同级目录),在无 dbeaver-common 的检出中执行 mvn verify -f product/aggregate/pom.xml 会因聚合模块缺失而失败;构建环境需满足 Java 21 与 Maven(Tycho 插件)要求。本文所有结论均取自仓库内文档与源码,如 AGENTS.md、AGENTS-Architecture.md、AGENTS-New-Database-Driver.md 及各插件的 MANIFEST.MF/pom.xml,行级细节以仓库实际内容为准。
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