文件存储引擎模块封装和使用分享
文件存储引擎模块封装和使用分享
背景
需求
在项目开发过程中,经常会使用到文件存储相关的功能,如:
- 存储发票文件
- 提供发票下载地址
- ……
调研
诸如此类的功能就需要使用到本地存储或云服务商提供的存储功能。当然,这对于开发高手的 zone 来说都是小意思,上网一查,对象存储哪家强?
第一位赫然显示了百家号创作者推荐的阿里云 OSS 服务,那行,就你吧,还要赶紧摸鱼等下班呢。接 API 嘛,小意思分分钟搞定,写个工具类封装一点上传下载方法那有多难。
开发
在下班点过了 1 小时之后 zone 终于写完了基于 OSS 对象存储服务封装的 FileUploadUtil.java
,并且与业务方法结合,实现了产品的需求。
身为同事的你问:「为什么是 FileUploadUtil
,光上传了那下载呢?」
zone 淡定回答:「奥,下载也在工具类里面,用 OssUtil
命名怕后来的同事找不到,FileUploadUtil
多见名知意呀。」
你问:「下载方法也在里面那为什么不用 FileUtil
命名工具类呢?」
zone 淡定回答:「当然是因为 FileUtil
被之前的开发占用掉了,我这个工具类里面有云存储,当然比 FileUtil
更高级咯,得区分开来。」
你问:「行吧,大佬 NB,回头我直接抄了昂。」
zone 淡定回答:「随便用。」
多项目复用
半年时间匆匆流逝,曾经的的 FileUploadUtil
工具类随着 zone 和同事娴熟的 CV 大法,在公司的项目里遍地开花。闲暇时间,每当看到新接手的项目中不是由自己 V 过去的 FileUploadUtil
,自豪感爆棚,我太牛了。
服务商迁移
但是好景不长,今天新来的技术总监说 OSS 的云服务太贵了,我们要「降本」,换 AWS 的 S3 对象存储吧,能免费用一年,所有项目都给我迁。随着总监的一声令下,正摸鱼的 zone 不爽了,由于公司里 80% 的项目用的都是 FileUploadUtil
,迁移的事情不出所料的落在了自己头上。得,曾经觉的自己有多牛,今天就觉的自己有多苦。活还是得干,zone 看了一下 S3 的接口文档,刷刷刷的把 FileUploadUtil
给改了,顺便把剩下的 20% 项目里也 V 过去了新改到接入 S3 的 FileUploadUtil
。
技术总监验收之后说:「小伙子你很不错,降本这件事情我记你一笔。」zone 就这样亲眼看到总监真就记了一笔,再也没有下文了。半个月后,期待的升职加薪还没有发生,新的运维总监来了,直接用数据安全问题为由说服了爱国老板,又要把对象存储迁回 OSS。这回 zone 连人都没见,也不知道缘由,就看到任务系统来了个紧急迁移任务。技术总监也是够懒,标题「云存储」内容直接就三字「迁回去」。zone 看了看手里的奶茶和任务系统里的驳回选项,忍住了嘴里的爆珠还是选择嚼碎了吞下去,毕竟生活不易。
多重实现 P0 事件
就是这次,还发现了一些隐藏问题,之前的那 20% 的项目中,为了抓紧时间下班陪妹子,并没有把别的同事写的 ossClient
对象删除掉,程序可不惯着,直接启动失败。
***************************
APPLICATION FAILED TO START
***************************
Description:
The bean 'ossClient', defined in class path resource [com/zonezzc/FileUploadUtil.class], could not be registered. A bean with that name has already been defined in class path resource [com/zonezzc/OssConfiguration.class] and overriding is disabled.
Action:
Consider renaming one of the beans or enabling overriding by setting spring.main.allow-bean-definition-overriding=true
已与地址为 ''127.0.0.1:52291',传输: '套接字'' 的目标虚拟机断开连接
修复这个问题的同时,zone 仔细一看,这还不是最坑的,竟然还有更多的 ossClient
实现类并不叫这个名字,叫什么 ossClient1
、ossClient2
,并且虽然已经切换了有半个月了,由于之前没有关注到这种现象,截止到今天竟然还有文件的上传和下载还在使用 OSS 的服务,吓的 zone 出了一身冷汗,赶紧修复了问题并上报了技术总监。技术总监也不含糊,10 分钟后就定了个 P0 事件给捅上去了 20 分钟后全公司就通过邮件知道了 zone 这个名字。
复盘
经过这次 P0 事件,zone 痛定思痛,决定复盘并从根本上解决这类问题。
之前存在的技术问题
- 工具类的使用没有在公司内进行培训,导致 CV 现象和重新开发并存,没有形成统一。
- 没有考虑文件存储服务商变更的可能性,导致服务商变更之后不能实现快速安全切换。
- 没有抽象文件存储功能,
FileUploadUtil
工具类代码侵入性太高,没有与业务系统解耦。
zone 把脑袋一拍,有了一个大胆的想法,不如就趁这次,设计一个文件存储引擎。
概念
设计
模板模式
效果
第一版
实现内容
.
├── java
│ └── com
│ └── zonezzc
│ └── storage
│ └── engine
│ ├── StorageApplication.java
│ ├── config
│ │ ├── CosStorageEngineConfig.java
│ │ ├── KodoStorageEngineConfig.java
│ │ └── OssStorageEngineConfig.java
│ ├── core
│ │ ├── AbstractStorageEngine.java
│ │ ├── StorageEngine.java
│ │ └── context
│ │ ├── DeleteFileContext.java
│ │ ├── DownloadUrlContext.java
│ │ ├── ReadFileContext.java
│ │ └── StoreFileContext.java
│ ├── cos
│ │ └── CosStorageEngine.java
│ ├── kodo
│ │ └── KodoStorageEngine.java
│ ├── oss
│ │ └── OssStorageEngine.java
│ └── utils
│ └── FileUtils.java
└── resources
├── application-dev.yml
├── application-prod.yml
├── application-test.yml
└── application.yml
# application.yml
storage:
engine:
oss:
endpoint: oss-cn-shanghai.aliyuncs.com
accessKeyId: xxxxxxxxxxxxxxxxxxxxxxxx
accessKeySecret: xxxxxxxxxxxxxxxxxxxxxxxx
bucketName: zonezzc
cos:
secretId: xxxxxxxxxxxxxxxxxxxxxxxx
secretKey: xxxxxxxxxxxxxxxxxxxxxxxx
region: ap-shanghai
bucketName: zonezzc-1253326811
kodo:
region: z2
accessKey: xxxxxxxxxxxxxxxxxxxxxxxx
secretKey: xxxxxxxxxxxxxxxxxxxxxxxx
bucketName: zonezzc
使用方式
CV 大法,在项目中把所有代码复制粘贴,人工适配
注入 StorageEngine 对象
@Resource
private StorageEngine storageEngine;
使用 StorageEngine 提供的文件上传下载方法
第二版
实现内容
使用方式
- 引入对应的文件存储引擎依赖
- 根据提示配置
applecation.yml
- 注入
StorageEngine
对象 - 使用
StorageEngine
提供的文件上传下载方法
引入依赖
<dependency>
<groupId>com.zonezzc</groupId>
<artifactId>storage-engine-oss</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
配置引擎需要的信息
com:
zonezzc:
storage:
engine:
oss:
access-key-id: xxxxxxxxxxxxxxxxxxxxxxxx
access-key-secret: xxxxxxxxxxxxxxxxxxxxxxxx
endpoint: oss-cn-shanghai.aliyuncs.com
bucket-name: zonezzc
auto-create-bucket: true
注入 StorageEngine 对象
@Resource
private StorageEngine storageEngine;
使用 StorageEngine 提供的文件上传下载方法