一序列化与反序列化 在大型开发中,序列化与反序列化是一个常见的技术点和问题。在之前我们对序列化与反序列化有过相关描述,但并不系统,更偏重于原理介绍。这里,我们将详细介绍序列化与反序列化的更多场景和应用实践。 序列化protobuf的编码结构二概念回顾 当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。 把Java对象转换为字节序列的过程称为对象的序列化。 把字节序列恢复为Java对象的过程称为对象的反序列化。三技术方案3。1google的protobuffer 早期google原生的protobuffer使用起来相当麻烦,首先要写。proto文件,然后编译。proto文件,生成对应的。java文件,过程较为繁琐。不过目前随着protobufjava等jar包的提供,使用也简化了很多。github地址:https:github。comtopicsprotobuffer。3。2Java的序列化与反序列化 根据Thinkinginjava3rdEdition的描述: 利用对象序列化可以实现轻量级持久化(lightweightpersistence)。持久化意味着一个对象的生存周期并不取决于程序是否正在执行;它可以生存于程序的调用之间。通过将一个序列化对象写入磁盘,然后在重新调用时恢复该对象,就能够实现持久化的效果。之所以称其为轻量级,是因为不能用某种persistent(持久)关键字来简单地定义一个对象,并让系统自动维护其他细节问题(尽管将来有可能实现)。相反,对象必须在程序中显式地序列化和重组。如果需要一个更严格的持久化机制,可以考虑使用Java数据对象(JDO)或者像Hibernate之类的工具。 对象序列化的概念加入到语言中是为了提供对两种主要特性的支持: Java的远程方法调用(RMI,RemoteMethodInvocation)使存活于其他计算机上的对象使用起来就像是存活于本机上一样。当向远程对象发送消息时,需要通过对象序列化来传输参数和返回值。 对JavaBeans来说对象序列化也是必需的。使用一个Bean时,一般情况下是在设计阶段对它的状态信息进行配置。这种状态信息必须保存下来,并在程序启动以后,进行恢复;具体工作由对象序列化完成。3。3io。protostuff 这是最近在项目中使用到的一个框架,本篇也将先详细描述相关的使用案例,作为本系列的开篇。四使用示例4。1引入maven依赖 使用的是1。5。3版本:dependencygroupIdio。protostuffgroupIdprotostuffruntimeartifactIdversion1。5。3versiondependencydependencygroupIdio。protostuffgroupIdprotostuffcoreartifactIdversion1。5。3versiondependency4。2定义实体类4。2。1ProtoBufEntitypackagecom。flamingskys。toolbox。tool。protobuf。importlombok。DDatapublicclassProtoBufEntity{privateSprivateSpublicProtoBufEntity(){}publicProtoBufEntity(Stringname,Integerage){this。this。}}4。2。2GroupEntity 这是一个嵌套实体类,包含了上面的ProtoBufEntity:packagecom。flamingskys。toolbox。tool。protobuf。importlombok。Dimportjava。util。LDatapublicclassGroupEntity{privateSprivateSprivateListProtoBufEpublicGroupEntity(Stringid,Stringname,ListProtoBufEntityentities){this。this。this。}}4。2。3应用类ProtoStuffUtilspackagecom。flamingskys。toolbox。tool。importcom。flamingskys。toolbox。tool。protobuf。entity。GroupEimportcom。flamingskys。toolbox。tool。protobuf。entity。ProtoBufEimportio。protostuff。LinkedBimportio。protostuff。ProtostuffIOUimportio。protostuff。Simportio。protostuff。runtime。RuntimeSimportjava。util。ArrayLimportjava。util。Limportjava。util。Mimportjava。util。concurrent。ConcurrentHashMpublicclassProtoStuffUtils{避免每次序列化都重新申请Buffer空间privatestaticLinkedBufferbufferLinkedBuffer。allocate(LinkedBuffer。DEFAULTBUFFERSIZE);缓存SchemaprivatestaticMapC?,S?schemaCachenewConcurrentHashMapC?,S?();序列化方法,把指定对象序列化成字节数组paramobjparamTreturnSuppressWarnings(unchecked)publicstaticTbyte〔〕serialize(Tobj){ClassTclazz(ClassT)obj。getClass();SchemaTschemagetSchema(clazz);byte〔〕try{dataProtostuffIOUtil。toByteArray(obj,schema,buffer);}finally{buffer。clear();}}反序列化方法,将字节数组反序列化成指定Class类型paramdataparamclazzparamTreturnpublicstaticTTdeserialize(byte〔〕data,ClassTclazz){SchemaTschemagetSchema(clazz);Tobjschema。newMessage();ProtostuffIOUtil。mergeFrom(data,obj,schema);}SuppressWarnings(unchecked)privatestaticTSchemaTgetSchema(ClassTclazz){SchemaTschema(SchemaT)schemaCache。get(clazz);if(schemanull){这个schema通过RuntimeSchema进行懒创建并缓存所以可以一直调用RuntimeSchema。getSchema(),这个方法是线程安全的schemaRuntimeSchema。getSchema(clazz);if(schemanull){schemaCache。put(clazz,schema);}}}publicstaticvoidmain(String〔〕args){finalProtoBufEntityentity1newProtoBufEntity(aaa,20);finalProtoBufEntityentity2newProtoBufEntity(bbb,21);ListProtoBufEntityentitysnewArrayListProtoBufEntity(){{add(entity1);add(entity2);}};GroupEntitygroupnewGroupEntity(id1,group1,entitys);byte〔〕bytesProtoStuffUtils。serialize(group);System。out。println(序列化后:bytes。length);GroupEntitygroup1ProtoStuffUtils。deserialize(bytes,GroupEntity。class);System。out。println(反序列化后:group1。getName());}}