作者:Zonezzc
最后更新时间:2023-11-15 17:56:16
背景
需求
在项目开发过程中,经常会使用到文件存储相关的功能,如:
- 存储发票文件
- 提供发票下载地址
- ……
调研
诸如此类的功能就需要使用到本地存储或云服务商提供的存储功能。当然,这对于开发高手的 zone 来说都是小意思,上网一查,对象存储哪家强?
image第一位赫然显示了百家号创作者推荐的阿里云 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
对象删除掉,人是偷了懒,但程序可不惯着,这回 zone 在把 FileUploadUtil
换回来的时候,项目直接启动失败。这咋回事啊,查看报错信息,原来是有同名 Bean!
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
Bean 并不叫这个名字,叫什么 ossClient1
、ossClient2
,由于之前没有仔细检查,在切换了 S3 服务半个月后的今天,竟然还有文件的上传和下载在使用 OSS 服务,这把 zone 吓得出了一身冷汗,赶紧修复了代码并上报了技术总监。技术总监也不含糊,10 分钟后就定了个 P0 事件给捅上去了,20 分钟后全公司就通过邮件知道了 zone 这个名字,通宵达旦的问题修复就此展开了序幕。
复盘
经过这次 P0 事件,zone 痛定思痛,决定从根本上解决。
之前存在的技术问题
- 工具类的使用没有在公司内进行培训,导致 CV 现象和重新开发并存,没有形成统一。
- 没有考虑文件存储服务商变更的可能性,导致服务商变更之后不能实现快速安全切换。
- 没有抽象文件存储功能,
FileUploadUtil
工具类代码侵入性太高,没有与业务系统解耦。
看着这些问题,zone 把脑袋一拍,接着就有了一个大胆的想法,不如就趁这次,设计一个「文件存储引擎」。
概念
image设计
模板模式
StorageEngine效果
第一版
实现内容
.
├── 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 提供的文件上传下载方法
image第二版
实现内容
image使用方式
- 引入对应的文件存储引擎依赖
- 根据提示配置
applecation.yml
- 注入
StorageEngine
对象 - 使用
StorageEngine
提供的文件上传下载方法
引入依赖
<dependency>
<groupId>com.zonezzc</groupId>
<artifactId>storage-engine-oss</artifactId>
<version>0.0.1</version>
</dependency>
配置引擎需要的信息
imagecom:
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;
网友评论