本文将带你完整走一遍开源 Java SDK 的开发与发布流程,从项目架构设计到成功发布到 Maven Central,让全球开发者都能通过一行依赖引入你的 SDK。
一、基础概念:API vs SDK
在开始之前,先搞清楚两个经常被混淆的概念。
1.1 什么是 API?
API(Application Programming Interface,应用程序编程接口) 是一组定义好的规则和协议,用于不同软件系统之间的通信。
简单来说,API 就像餐厅的菜单:
-
• 菜单告诉你有什么菜(端点) -
• 每道菜需要什么配料(参数) -
• 上菜的形式(响应格式)
1.2 什么是 SDK?
SDK(Software Development Kit,软件开发工具包) 是一套封装好的工具集,帮助开发者更方便地使用 API。
SDK 就像餐厅的外卖 App:
-
• 你不需要记住菜单上的所有菜名 -
• 不需要自己打电话点餐 -
• 点几下按钮,饭就送到了
1.3 API vs SDK 对比
|
|
|
|
| 代码量 |
|
|
| 类型安全 |
|
|
| 学习成本 |
|
|
| 维护成本 |
|
|
1.4 代码对比示例
直接调用 API:
// 需要手写大量代码
HttpClientclient= HttpClient.newHttpClient();
HttpRequestrequest= HttpRequest.newBuilder()
.uri(URI.create("https://api.example.com/users/123"))
.header("Authorization", "Bearer " + token)
.header("Content-Type", "application/json")
.GET()
.build();
HttpResponse<String> response = client.send(request,
HttpResponse.BodyHandlers.ofString());
// 手动解析 JSON
Gsongson=newGson();
Useruser= gson.fromJson(response.body(), User.class);
使用 SDK:
// 一行代码搞定
User user = client.users().get(123);
二、为什么要开发 SDK?
当你频繁调用某个第三方 API 时,每次都要手写 HTTP 请求、处理响应、解析 JSON... 这些重复劳动不仅耗时,还容易出错。
SDK(Software Development Kit) 就是为了解决这个问题而生的:
-
• 封装复杂性:将 HTTP 请求、签名、重试等逻辑封装起来 -
• 类型安全:提供强类型的请求/响应对象,编译时就能发现错误 -
• 开发体验:IDE 智能提示,降低使用门槛 -
• 统一维护:API 变更时只需更新 SDK,下游用户升级版本即可
三、设计模式详解
在编写 SDK 之前,需要了解两个核心设计模式。
3.1 Builder 模式(建造者模式)
问题场景:当一个对象有很多可选参数时,构造函数会变得很复杂。
Builder 模式解决方案:
代码示例:
// Builder 模式 - 链式调用,清晰易读
Client client = new ClientBuilder()
.token("your-token") // 必需参数
.timeout(10000) // 可选,有默认值
.retryCount(3) // 可选,有默认值
.baseUrl("https://...") // 可选,有默认值
.build();
Builder 模式的优点:
-
1. 可读性强:每个参数都有名字,一目了然 -
2. 灵活性高:可选参数可以省略,使用默认值 -
3. 不可变性:build() 后返回不可变对象 -
4. 参数校验:可以在 build() 时统一校验
3.2 门面模式(Facade Pattern)
问题场景:系统内部有很多复杂的子系统,直接暴露给用户会让人崩溃。
门面模式解决方案:
代码示例:
// 用户只需要和 Client 这一个"门面"打交道
Client client = new ClientBuilder().token("xxx").build();
// 所有复杂性都被隐藏了
List<Group> groups = client.groups().list();
Topic topic = client.topics().get(topicId);
User me = client.users().getMe();
门面模式的优点:
-
1. 简化接口:用户只需要了解一个入口 -
2. 解耦:用户代码和内部实现解耦 -
3. 易于使用:降低学习成本 -
4. 灵活重构:内部实现可以随意修改,不影响用户
四、SDK 架构设计
一个优秀的 SDK 需要清晰的架构设计,以我这两天做的知识星球 SDK 为例,以下是推荐的分层架构:
4.1 核心组件说明
|
|
|
|
| Client |
|
client.groups().list() |
| ClientBuilder |
|
|
| Request 模块 |
|
|
| HttpClient |
|
|
| Models |
|
|
| Exceptions |
|
|
4.2 异常设计
良好的异常设计能让用户快速定位问题:
五、项目结构
推荐使用 Monorepo 管理多语言 SDK:
my-sdk/
├── spec/ # API 规范 (SSOT)
│ ├── openapi.yaml # OpenAPI 规范
│ ├── errors/ # 错误码定义
│ └── sdk-design/ # SDK 设计规范
├── packages/
│ ├── java/ # Java SDK
│ │ ├── pom.xml
│ │ └── src/
│ │ ├── main/java/com/example/sdk/
│ │ │ ├── Client.java
│ │ │ ├── ClientBuilder.java
│ │ │ ├── http/
│ │ │ │ └── HttpClient.java
│ │ │ ├── request/
│ │ │ │ ├── GroupsRequest.java
│ │ │ │ ├── TopicsRequest.java
│ │ │ │ └── UsersRequest.java
│ │ │ ├── model/
│ │ │ │ ├── Group.java
│ │ │ │ ├── Topic.java
│ │ │ │ └── User.java
│ │ │ └── exception/
│ │ │ ├── BaseException.java
│ │ │ └── AuthException.java
│ │ └── test/
│ ├── typescript/ # TypeScript SDK
│ ├── go/ # Go SDK
│ └── python/ # Python SDK
└── docs/ # 文档
六、核心代码实现
6.1 Builder 模式构建客户端
public classClientBuilder {
private String token;
privateinttimeout=10000;
privateintretryCount=3;
public ClientBuilder token(String token) {
this.token = token;
returnthis;
}
public ClientBuilder timeout(int timeout) {
this.timeout = timeout;
returnthis;
}
public Client build() {
if (token == null || token.isEmpty()) {
thrownewIllegalArgumentException("Token is required");
}
returnnewClient(this);
}
}
6.2 门面类设计
public classClient {
privatefinal GroupsRequest groups;
privatefinal TopicsRequest topics;
privatefinal UsersRequest users;
Client(ClientBuilder builder) {
HttpClienthttpClient=newHttpClient(builder);
this.groups = newGroupsRequest(httpClient);
this.topics = newTopicsRequest(httpClient);
this.users = newUsersRequest(httpClient);
}
public GroupsRequest groups() { return groups; }
public TopicsRequest topics() { return topics; }
public UsersRequest users() { return users; }
}
6.3 使用示例
// 创建客户端
Clientclient=newClientBuilder()
.token("your-token")
.timeout(10000)
.build();
// 获取列表
List<Group> groups = client.groups().list();
// 获取详情
Topictopic= client.topics().get(topicId);
// 获取当前用户
Userme= client.users().getMe();
七、发布到 Maven Central
这是本文的重点!让我们一步步完成发布流程。
7.1 发布流程总览
7.2 配置 pom.xml
Maven Central 对 pom.xml 有严格要求,必须包含以下信息:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- 基本信息 -->
<groupId>io.github.your-username</groupId>
<artifactId>your-sdk</artifactId>
<version>1.0.0</version>
<packaging>jar</packaging>
<!-- 项目描述(必需) -->
<name>your-sdk</name>
<description>Your SDK Description</description>
<url>https://github.com/your-username/your-sdk</url>
<!-- 开源许可证(必需) -->
<licenses>
<license>
<name>MIT License</name>
<url>https://opensource.org/licenses/MIT</url>
</license>
</licenses>
<!-- 开发者信息(必需) -->
<developers>
<developer>
<name>Your Name</name>
<email>your-email@example.com</email>
</developer>
</developers>
<!-- 源码管理(必需) -->
<scm>
<connection>scm:git:git://github.com/your-username/your-sdk.git</connection>
<developerConnection>scm:git:ssh://github.com:your-username/your-sdk.git</developerConnection>
<url>https://github.com/your-username/your-sdk/tree/main</url>
</scm>
<!-- 构建插件 -->
<build>
<plugins>
<!-- 源码包 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>3.3.0</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar-no-fork</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Javadoc -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>3.6.3</version>
<executions>
<execution>
<id>attach-javadocs</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- GPG 签名(必需) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<id>sign-artifacts</id>
<phase>verify</phase>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Central Publishing 插件 -->
<plugin>
<groupId>org.sonatype.central</groupId>
<artifactId>central-publishing-maven-plugin</artifactId>
<version>0.6.0</version>
<extensions>true</extensions>
<configuration>
<publishingServerId>central</publishingServerId>
<autoPublish>true</autoPublish>
</configuration>
</plugin>
</plugins>
</build>
</project>
7.3 GroupId 选择
GroupId 有两种选择:
|
|
|
|
| 域名反转 | com.example |
|
| GitHub 账号 | io.github.username |
|
**推荐使用 io.github.username**,无需域名验证,只需在 GitHub 创建一个特定名称的空仓库即可。
7.4 注册 Maven Central 账号
-
1. 访问 https://central.sonatype.com/ -
2. 使用 GitHub 账号登录 -
3. 进入 Namespaces 页面 -
4. 点击 Add Namespace -
5. 输入 io.github.your-username(替换为你的用户名) -
6. 按提示在 GitHub 创建验证仓库
7.5 生成 GPG 密钥
Maven Central 要求所有发布的 artifacts 必须经过 GPG 签名。
安装 GPG(macOS)
brew install gnupg
生成密钥
gpg --full-generate-key
按提示输入:
-
• 密钥类型: RSA and RSA(默认) -
• 密钥长度: 4096 -
• 有效期:根据需要选择 -
• 真实姓名:你的名字 -
• 邮箱:你的邮箱 -
• 密码短语:设置一个强密码(务必记住!)
查看密钥 ID
gpg --list-keys --keyid-format LONG
输出示例:
pub rsa4096/XXXXXXXXXXXXXXXX 2025-12-10 [SC]
YYYYYYYYYYYYYYYYYYYYYYYYYXXXXXXXXXXXXXXXX
uid [ 绝对 ] Your Name <your-email@example.com>
sub rsa4096/ZZZZZZZZZZZZZZZZ 2025-12-10 [E]
其中 XXXXXXXXXXXXXXXX 就是你的 Key ID。
上传公钥到密钥服务器
gpg --keyserver keyserver.ubuntu.com --send-keys YOUR_KEY_ID
7.6 生成 Central Portal Token
-
1. 登录 https://central.sonatype.com/ -
-
2. 点击右上角头像 → View Account -
-
3. 点击 Generate User Token -
-
4. 复制 username和password
7.7 配置 settings.xml
在 ~/.m2/settings.xml 中添加:
<?xml version="1.0" encoding="UTF-8"?>
<settings xmlns="http://maven.apache.org/SETTINGS/1.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.2.0
https://maven.apache.org/xsd/settings-1.2.0.xsd">
<servers>
<server>
<id>central</id>
<username>你的Token用户名</username>
<password>你的Token密码</password>
</server>
</servers>
</settings>
7.8 执行发布
cd packages/java
mvn clean deploy
发布过程中 GPG 会提示输入密码短语,输入后等待上传完成。
7.9 验证发布结果
-
1. 访问 https://central.sonatype.com/ 查看发布状态 -
-
2. 同步到 Maven Central 搜索索引需要 10-30 分钟 -
3. 完全同步可能需要 几小时 -
八、常见问题
Q1: GPG 签名失败 "Inappropriate ioctl for device"
这是因为 GPG 无法在非交互式终端中请求密码。解决方案:
# 配置 GPG 使用 loopback 模式
mkdir -p ~/.gnupg
echo "pinentry-mode loopback" >> ~/.gnupg/gpg.conf
echo "allow-loopback-pinentry" >> ~/.gnupg/gpg-agent.conf
gpgconf --kill gpg-agent
Q2: 编译失败 "symbol not found"
通常是 Lombok 版本与 Java 版本不兼容:
-
• Java 21 需要 Lombok 1.18.30+ -
• 不要使用 SNAPSHOT 版本发布到 Central
Q3: 发布后在 Maven Central 搜不到
新发布的 artifacts 需要时间同步:
-
• 直接通过坐标引用:约 10-30 分钟 -
• 在 search.maven.org 搜索:可能需要几小时
九、发布后的使用
发布成功后,用户可以这样引入你的 SDK:
Maven
<dependency>
<groupId>io.github.your-username</groupId>
<artifactId>your-sdk</artifactId>
<version>1.0.0</version>
</dependency>
Gradle
implementation 'io.github.your-username:your-sdk:1.0.0'
Gradle (Kotlin DSL)
implementation("io.github.your-username:your-sdk:1.0.0")
十、总结
看完以上的案例,你就能知道,发布一个开源 SDK 到 Maven Central 的完整流程包含这几个阶段:
关键要点:
-
1. 理解概念:API 是接口规范,SDK 是封装好的工具包 -
2. 设计模式:Builder 模式构建对象,门面模式简化接口 -
3. 架构设计:清晰的分层,职责分明 -
4. pom.xml 配置:必须包含 name、description、url、licenses、developers、scm -
5. GPG 签名:必需,用于验证 artifacts 完整性 -
6. groupId 选择:推荐使用 io.github.username,验证简单
希望这篇文章能帮助你成功发布自己的开源 SDK!如果有任何问题,欢迎在评论区交流。
相关链接:
-
• Maven Central Portal -
• Central Publishing 插件文档 -
• GPG 密钥管理 -
我是易安,一位专注AI技术研究的AI超级个体。每天为大家带来前沿AI工具评测和实践经验,用通俗易懂的方式解读复杂的技术概念,👇长按扫码关注,一起探索AI技术的无限可能!
如果觉得我的文章对你有帮助的话,可以帮我点个赞👍或者喜欢❤,让更多跟你一样好品味的人看到这些内容,感谢🙏
推荐阅读
来,这是易安的介绍(第2版,交个朋友,限时送福利) 我和深圳大冲的故事

