candy-s3:一个让你少操心的对象存储封装库

10 阅读5分钟

candy-s3:一个让你少操心的对象存储封装库

大家好!今天想和大家聊聊 candy-s3 —— 一个轻量、可靠、专为“省事”而生的跨云对象存储封装库。如果你曾经被多云对象存储的 SDK 折磨过,或者只是想快速搞定上传下载,又不想被一堆配置和依赖拖慢节奏,那它可能正是你一直在找的工具。

为什么会有 candy-s3?

当今开发中,对象存储早已不是“选不选”的问题,而是“怎么用得更顺手”。但现实往往很骨感:

  • 多厂商 SDK 集成太重:AWS S3、阿里云 OSS、腾讯云 COS……虽然每个都声称是AWS S3 compatible,但是每个都有自己的 SDK,项目一支持多云,依赖就爆炸,引入了一堆SDK却只用到了GetObject/PutObject。
  • 原生 S3 SDK 学习成本高:哪怕只是上传个文件,也得搞懂 credential chain、region、builder 嵌套、异常分类……
  • 自己封装又怕翻车:不同厂商的 S3 兼容接口总有细微差异(比如分片大小限制、分页行为),没做足测试,线上就容易出问题;接口设计不好,后续迭代更是灾难。

能不能一套代码、兼容多云呢?在github搜了半天,居然真没有合适的项目。

于是,我们做了 candy-s3 —— 一个基于 Java 的轻量级封装库,直接对接AWS S3 API,根据AWS S3标准定义接口规范,之后不管你用r2,oss,cos,obs,minio,只要是AWS S3 Compatible,就都通用!目标很简单:让你用最熟悉的 S3 操作方式,一次写代码,到处跑服务


它能为你解决什么?

原生 S3 接口对齐,零额外学习成本

candy-s3 的 API 设计完全遵循 S3 的操作语义。你会用 putObjectgetObjectlistObjects,就能立刻上手,不需要学任何新概念。更重要的是,它内部已经帮你屏蔽了不同厂商 S3 兼容服务的差异,真正做到“一次编码,多云适配”。

多云无缝兼容,切换后端只需改配置

无论是:

  • AWS S3
  • 阿里云 OSS
  • 腾讯云 COS
  • Cloudfalre R2
  • MinIO(私有化部署)
  • 其他对象存储服务...(obs,qiniu,others...)

只要支持标准 S3 协议,candy-s3 就能直接对接,不用引入每个云厂商的一堆存储、认证、签名sdk。换存储后端,不用动业务代码,只改 endpoint 和密钥就行。

完备单元测试,可靠性有保障,单元测试即文档

一个开源工具要进生产环境,稳定比功能更重要,文档比代码更重要,而最好的文档就是代码。在这个项目上投入的80%以上时间,都用在了编写单元测试——引入后你甚至不需要手写代码,copy单元测试就覆盖了你能用到的所有对象存储场景。不仅覆盖了 Put、Get、List、MultipartUpload分片上传 等核心操作,还包含了Versioning版本控制、Condition Write条件写入、ObjectLock对象锁、LegalHold合法保留、SSE服务端加密等高级特性,异常情况、边界条件都有验证。

接口稳定 + 依赖精简,长期维护无压力

  • 接口定义文档,保持向后兼容,绝不轻易 break your code
  • 仅依赖 Jackson 和 OkHttp 这两个成熟、轻量的第三方库(我相信你代码本身就依赖了他们),没有冗余依赖,减少冲突风险
  • 遵循“接口不变,实现可扩展”的原则,未来新增功能也不会影响现有调用。

开发者有意在新版本中将OkHttp也移除,直接使用java内置http库,进一步精简依赖


来看看实际怎么用?

单元测试就是最好的文档,引入后你甚至不需要手写代码,copy单元测试就覆盖了你能用到的所有对象存储场景

1. 引入依赖(Maven)

<dependency>
    <groupId>io.github.matian2014</groupId>
    <artifactId>candy-s3</artifactId>
    <version>1.0.0</version>
</dependency>

2. 初始化客户端

// Create AWS S3 client
CandyS3 client = new CandyS3(S3Provider.AWS);
client.setAccessKey("your-access-key");
client.setSecretKey("your-secret-key");
client.setRegion("us-east-1");

3. 上传文件(Put)

// Upload object
String content = "Hello, World!";
PutObjectOptions putOptions = new PutObjectOptions.PutObjectOptionsBuilder()
        .configureUploadData().withData(content.getBytes()).endConfigureDataContent()
        .build();
String etag = client.putObject("my-bucket", "my-object", putOptions);

candy-s3d的putObject()方法支持对大对象自动化分片上传

4. 下载文件(Get)

// Download object
DownloadObjectOptions downloadOptions = new DownloadObjectOptions.DownloadObjectOptionsBuilder()
        .configureDataOutput().toBytes().endConfigureDataOutput()
        .build();
S3Object object = client.getObject("my-bucket", "my-object", downloadOptions);

5. 手动分片上传(Multipart Upload)

String objectKey = "multipartUploadObject.data";
String uploadId = candyS3.createMultipartUpload(bucket, objectKey,
        new CreateMultipartUploadOptions.CreateMultipartUploadOptionsBuilder().build());
        
List<S3Part> parts = new ArrayList<>();
S3Part part11 = candyS3.uploadPart(bucket, objectKey, uploadId, 1,
            new UploadPartOptions.UploadPartOptionsBuilder()
                    .configureUploadData()
                    .withData(Arrays.copyOfRange(bytes, 0, 5 * 1024 * 1024))
                    .endConfigureDataContent()
                    .build());
parts.add(part11);
S3Part part12 = candyS3.uploadPart(bucket, objectKey, uploadId, 2,
            new UploadPartOptions.UploadPartOptionsBuilder()
                    .configureUploadData()
                    .withData(Arrays.copyOfRange(bytes, 5 * 1024 * 1024, bytes.length))
                    .endConfigureDataContent()
                    .build());
parts.add(part12);
candyS3.completeMultipartUpload(bucket, objectKey, uploadId, parts,
            new CompleteMultipartUploadOptions.CompleteMultipartUploadOptionsBuilder().build());

适合哪些场景?

  • 中小型项目:不想引入重型 SDK,只想快速实现文件上传下载。
  • 多云/混合云架构:需要灵活切换存储后端,但不想每次重写适配层。
  • MinIO 私有化部署:希望有一套标准、可靠的 Java 客户端统一管理。
  • 快速原型验证:今天有个想法,明天就想跑通存储逻辑?candy-s3 能帮你省下大半天。
  • 云服务功能完备性验证:不确定迁移对象存储服务商后功能完备性,candy-s3跑一轮单元测试一目了然

生产环境怎么用得更好?

虽然 candy-s3 已经足够稳定,但在生产中还是建议注意几点:

  • 配置优化:根据网络环境设置合理的连接/读取超时。
  • 异常处理 + 重试:建议封装通用异常处理逻辑,并对网络波动类错误(如 SocketTimeoutException)引入重试机制(例如用 Guava Retrying)。
  • 权限最小化:访问密钥务必遵循“最小权限原则”,避免泄露;公开对象可通过 ACL 控制,无需在代码里硬编码权限逻辑。

未来计划 & 欢迎共建!

目前 candy-s3 1.0.0 已覆盖日常 90%+ 的使用场景,并将长期持续维护。

非常欢迎你来参与! 欢迎Issue,欢迎PR,更期待你的Star!

项目采用标准 Git Flow 工作流,代码清晰,测试完备,新手也能快速上手。

GitHub 地址:github.com/matian2014/…

Gitee 地址:gitee.com/connormma/c…