如何将从Amazon S3获取的对象反序列化为Java自定义类对象
实现方案
核心逻辑很简单:S3Object是S3返回的响应包装类,直接调用它的getObjectContent()方法就能拿到存储文件的原始输入流,把这个流传入对应序列化框架的反序列化方法,就能得到MyClass实例。
注意:反序列化使用的协议、工具版本,必须和你当初把
MyClass实例写入S3时使用的完全一致,否则会出现反序列化失败、字段值错乱的问题。
具体代码实现
所有流、S3对象都要在finally块里关闭,避免资源泄漏,下面分两种最常见的存储场景给出可直接复用的代码:
场景1:存储时使用Java原生序列化
如果你的MyClass实现了java.io.Serializable接口,当初是用ObjectOutputStream把实例写入S3的,直接用ObjectInputStream读取流即可:
import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3ClientBuilder; import com.amazonaws.services.s3.model.GetObjectRequest; import com.amazonaws.services.s3.model.S3Object; import com.amazonaws.auth.profile.ProfileCredentialsProvider; import com.amazonaws.regions.Regions; import java.io.IOException; import java.io.ObjectInputStream; public class S3DeserializeDemo { public static void main(String[] args) { Regions clientRegion = Regions.DEFAULT_REGION; String bucketName = "你的存储桶名称"; // key要写全路径,格式为「文件夹名/文件名」,不要漏文件夹前缀 String key = "folder/你的带编号的MyClass存储文件名"; S3Object fullObject = null; ObjectInputStream ois = null; MyClass result = null; try { AmazonS3 s3Client = AmazonS3ClientBuilder.standard() .withRegion(clientRegion) .withCredentials(new ProfileCredentialsProvider()) .build(); fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key)); ois = new ObjectInputStream(fullObject.getObjectContent()); // 强转为目标类型即可 result = (MyClass) ois.readObject(); // 后续直接使用result实例 } catch (IOException | ClassNotFoundException e) { e.printStackTrace(); } finally { // 按顺序关闭资源:先关输入流,再关S3Object try { if (ois != null) ois.close(); if (fullObject != null) fullObject.close(); } catch (IOException e) { e.printStackTrace(); } } } } // 自定义类必须实现Serializable接口,建议显式声明序列化ID class MyClass implements java.io.Serializable { private static final long serialVersionUID = 1L; // 正常编写类的字段、业务方法即可 }
场景2:存储时使用JSON序列化(生产环境最常用)
绝大多数场景不会用Java原生序列化存储对象,一般是用Jackson、Fastjson这类JSON框架把对象转成JSON字符串后存入S3,这种情况直接用JSON工具从流解析对象即可,以Jackson为例:
引入Jackson依赖后,核心代码如下(S3Client构建逻辑和上面一致,不再重复):
try { fullObject = s3Client.getObject(new GetObjectRequest(bucketName, key)); ObjectMapper objectMapper = new ObjectMapper(); // 直接从流解析,不需要先转成字符串,性能更好 MyClass result = objectMapper.readValue(fullObject.getObjectContent(), MyClass.class); } catch (IOException e) { e.printStackTrace(); } finally { if (fullObject != null) { try { fullObject.close(); } catch (IOException e) { e.printStackTrace(); } } }
常见坑点提醒
- 填写
key参数时不要漏文件夹前缀,比如文件存放在<folder>目录下,key必须写为文件夹名/文件名,只写文件名会报404找不到对象 - 如果用Protobuf、Kryo、Hessian等其他序列化框架,逻辑完全一致:把
fullObject.getObjectContent()获取的输入流传入对应框架的反序列化方法,指定目标类型为MyClass即可 - 反序列化前确保本地的
MyClass类结构和序列化时的类结构一致,不要随意增删字段、修改字段类型,否则会反序列化失败
内容的提问来源于stack exchange,提问作者Rahul
相关产品推荐
相关产品推荐

