版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/alinyua/article/details/84201285
本文将实现一个包含JDK默认、Hessian、Json、Protostuff、Xml、Avro、ProtocolBuffer、Thrift等序列化方式的序列化引擎。用户可以提供使用 SerializerEngine 方便快捷地切换序列化方法实现。
文章目录
一 使用效果
执行代码如下:
@Data
public static class Person {
String name;
int age;
Date birth;
}
public static void main(String[] args){
Person person=new Person();
person.setName("li");
person.setAge(18);
person.setBirth(new Date());
out.println(person);
out.println("--------- Json序列化 ------------");
byte[] personBytes=SerializerEngine.serialize(person, SerializeTypeEnum.JSONSerializer);
out.println(new String(personBytes));
out.println("--------- Json反序列化 ---------------------");
person=SerializerEngine.deserialize(personBytes,Person.class,SerializeTypeEnum.JSONSerializer);
out.println(person);
out.println("---------- Xml序列化 -------------------");
personBytes=SerializerEngine.serialize(person, SerializeTypeEnum.XmlSerializer);
out.println(new String(personBytes));
out.println("---------- Xml反序列化 ------------------");
person=SerializerEngine.deserialize(personBytes,Person.class,SerializeTypeEnum.XmlSerializer);
out.println(person);
}
结果为:
二 总体结构
1 结构图
2 组件介绍
- ISerializer (序列化接口)
定义序列化和反序列化方法 - impl (序列化接口实现类)
实现序列化和反序列化方法 - SerializeTypeEnum (序列化枚举类)
一个不重复的数字code对应一个枚举类 - SerializerEngine (序列化引擎)
管理序列化枚举类和实现类的对应关系,并提供通用序列化与反序列化方法入口
序列化方法分类
- 不需要 IDL 工具
- 需有Serializable接口
- DefaultJavaSerializer
- HessianSerializer
- 不需有Serializable接口
- JSONSerializer
- XmlSerializer
- ProtoStuffSerializer
- 需有Serializable接口
- 需要 IDL 工具
- AvroSerializer
- ThriftSerializer
- ProtocolBufferSerializer
序列化方法场景推荐
如果不使用IDL的服务间传输的话,建议使用 ProtoStuffSerializer ,如果有可读性要求或是基于Ajax和移动APP通信的话就使用 JSONSerializer。
3 相互关系
用户直接使用 SerializerEngine 进行序列化和反序列化,通过传入 SerializeTypeEnum 指定序列化方法,SerializeTypeEnum和序列化方法的关系由 SerializerEngine 维护,序列化方法实现类实例 由SerializerEngine保存和管理。
三 结构实现
1 ISerializer
/**
* @version V1.0
* @author: lin_shen
* @date: 18-11-12
* @Description: 序列化接口
*/
public interface ISerializer {
/**
* 序列化
* @param obj 序列化对象
* @param <T> 序列化对象原始类型
* @return 字节数组
*/
<T> byte[] serialize(T obj);
/**
* 反序列化
* @param data 序列化字节数组
* @param clazz 原始类型的类对象
* @param <T> 原始类型
* @return
*/
<T> T deserialize(byte[] data, Class<T> clazz);
}
2 SerializeTypeEnum
注意这里每种序列化方式都对应了一个数字
/**
* @version V1.0
* @author: lin_shen
* @date: 18-11-18
* @Description: 序列化枚举类
*/
public enum SerializeTypeEnum {
/**
* Java默认序列化
*/
DefaultJavaSerializer(0),
/**
* Hessian序列化
*/
HessianSerializer(1),
/**
* Json序列化(基于Jackson)
*/
JSONSerializer(2),
/**
* Protostuff序列化
*/
ProtoStuffSerializer(3),
/**
* Xml序列化
*/
XmlSerializer(4),
/**
* Avro序列化,需借助IDL
*/
AvroSerializer(5),
/**
* ProtocolBuffer序列化,需借助IDL
*/
ProtocolBufferSerializer(6),
/**
* Thrift序列化,需借助IDL
*/
ThriftSerializer(7);
private int code;
SerializeTypeEnum(int code) {
this.code = code;
}
public static SerializeTypeEnum queryByCode (int code) {
for (SerializeTypeEnum type : values()) {
if(type.getCode()==code){
return type;
}
}
return null;
}
public int getCode() {
return code;
}
}
3 SerializerEngine
利用 SERIALIZER_MAP 管理 枚举和实现类的关系,提供可以指定序列化类型的入口方法
/**
* @version V1.0
* @author: lin_shen
* @date: 18-11-18
* @Description: 序列化引擎
*/
public class SerializerEngine {
private static final Map<SerializeTypeEnum, ISerializer> SERIALIZER_MAP = Maps.newConcurrentMap();
static {
SERIALIZER_MAP.put(SerializeTypeEnum.DefaultJavaSerializer, new DefaultJavaSerializer());
SERIALIZER_MAP.put(SerializeTypeEnum.HessianSerializer, new HessianSerializer());
SERIALIZER_MAP.put(SerializeTypeEnum.JSONSerializer, new JSONSerializer());
SERIALIZER_MAP.put(SerializeTypeEnum.XmlSerializer, new XmlSerializer());
SERIALIZER_MAP.put(SerializeTypeEnum.ProtoStuffSerializer, new ProtoStuffSerializer());
//以下三类不能使用普通的java bean,需借助IDL
SERIALIZER_MAP.put(SerializeTypeEnum.AvroSerializer, new AvroSerializer());
SERIALIZER_MAP.put(SerializeTypeEnum.ThriftSerializer, new ThriftSerializer());
SERIALIZER_MAP.put(SerializeTypeEnum.ProtocolBufferSerializer, new ProtocolBufferSerializer());
}
public static <T> byte[] serialize(T obj, SerializeTypeEnum serializeTypeEnum) {
ISerializer serializer = SERIALIZER_MAP.get(serializeTypeEnum);
return serializer.serialize(obj);
}
public static <T> T deserialize(byte[] data, Class<T> clazz, SerializeTypeEnum serializeTypeEnum) {
ISerializer serializer = SERIALIZER_MAP.get(serializeTypeEnum);
return serializer.deserialize(data, clazz);
}
}
四 各种序列化方法实现
1 DefaultJavaSerializer
效率低,局限于Java
/**
* @version V1.0
* @author: lin_shen
* @date: 18-11-18
* @Description: Java默认序列化(需有Serializable接口)
*/
public class DefaultJavaSerializer implements ISerializer {
@Override
public <T> byte[] serialize(T obj) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)){
objectOutputStream.writeObject(obj);
} catch (Exception e) {
throw new RuntimeException(e);
}
return byteArrayOutputStream.toByteArray();
}
@Override
public <T> T deserialize(byte[] data, Class<T> clazz) {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(data);
try {
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return (T) objectInputStream.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
2 HessianSerializer
使用方法和DefaultJavaSerializer类似,但效率高,而且跨语言,在大部分场景下可取代DefaultJavaSerializer(在某些情况下支持没有Java原生的好)
/**
* @version V1.0
* @author: lin_shen
* @date: 18-11-18
* @Description: Hessian序列化(需有Serializable接口)
*/
public class HessianSerializer implements ISerializer {
@Override
public byte[] serialize(Object obj) {
try(ByteArrayOutputStream os = new ByteArrayOutputStream()) {
HessianOutput ho = new HessianOutput(os);
ho.writeObject(obj);
return os.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public <T> T deserialize(byte[] data, Class<T> clazz) {
try(ByteArrayInputStream is = new ByteArrayInputStream(data)) {
HessianInput hi = new HessianInput(is);
return (T) hi.readObject();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
3 JSONSerializer
跨语言,可读性好,效率相对没那么高,这里用Jackson实现,可以完成很多定制
/**
* @version V1.0
* @author: lin_shen
* @date: 18-11-18
* @Description: Json序列化(基于jackson实现)
*/
public class JSONSerializer implements ISerializer {
/**
* ObjectMapper可配置json序列化规则,该类的创建需要消耗较多资源,故应配置为类成员对象
*/
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
static {
//允许字段名不带引号(这不符合JSON标准,但在JS中合法)
OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
//允许使用单引号代替双引号(这不符合JSON标准,但这一些JSON生成器中合法)
OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
//允许携带不加引号的控制字符(即ASCII码小于32的),不符合JSON标准,故默认为false
OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_CONTROL_CHARS, true);
//允许出现未定义处理方法(没有对应的setter方法或其他的处理器)的未知字段
OBJECT_MAPPER.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Override
public <T> byte[] serialize(T obj) {
try {
String json = OBJECT_MAPPER.writeValueAsString(obj);
return json.getBytes();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public <T> T deserialize(byte[] data, Class<T> clazz) {
String json = new String(data);
try {
return (T) OBJECT_MAPPER.readValue(json, clazz);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
4 XmlSerializer
大部分情况下可被Json取代
/**
* @author liyebing created on 17/1/21.
* @version $Id$
*/
public class XmlSerializer implements ISerializer {
private static final XStream xStream = new XStream(new DomDriver());
@Override
public <T> byte[] serialize(T obj) {
return xStream.toXML(obj).getBytes();
}
@Override
public <T> T deserialize(byte[] data, Class<T> clazz) {
String xml = new String(data);
return (T) xStream.fromXML(xml);
}
}
5 ProtoStuffSerializer
基于protostuff的protocolbuffer序列化工具,各方面效率都高,且不需要借助IDL(接口描述语言)
/**
* @version V1.0
* @author: lin_shen
* @date: 2018/11/18
* @Description: protobuf序列化工具(基于protostuff)
*/
public class ProtoStuffSerializer implements ISerializer {
/**
* 用于缓存类对象与Schema的对应关系,避免重复创建Schema
*/
private static final Map<Class<?>, Schema<?>> CACHED_SCHEMA = new ConcurrentHashMap<>();
/**
* 用于高效便捷地生成类实例,而无需构造方法支持
*/
private static final Objenesis OBJENESIS = new ObjenesisStd(true);
/**
* 序列化(对象 -> 字节数组)
*/
@Override
@SuppressWarnings("unchecked")
public <T> byte[] serialize(T obj) {
Class<T> cls = (Class<T>) obj.getClass();
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Schema<T> schema = getSchema(cls);
return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
buffer.clear();
}
}
/**
* 反序列化(字节数组 -> 对象)
*/
@Override
public <T> T deserialize(byte[] data, Class<T> cls) {
try {
T message = OBJENESIS.newInstance(cls);
Schema<T> schema = getSchema(cls);
ProtostuffIOUtil.mergeFrom(data, message, schema);
return message;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
@SuppressWarnings("unchecked")
private <T> Schema<T> getSchema(Class<T> cls) {
Schema<T> schema = (Schema<T>) CACHED_SCHEMA.get(cls);
if (schema == null) {
schema = RuntimeSchema.createFrom(cls);
CACHED_SCHEMA.put(cls, schema);
}
return schema;
}
}
6 AvroSerializer
需要借助IDL
/**
* @version V1.0
* @author: lin_shen
* @date: 2018/11/18
* @Description: AvroSerializer(只能序列化IDL产生的类)
*/
public class AvroSerializer implements ISerializer {
@Override
public <T> byte[] serialize(T obj) {
try {
DatumWriter userDatumWriter = new SpecificDatumWriter(obj.getClass());
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
BinaryEncoder binaryEncoder = EncoderFactory.get().directBinaryEncoder(outputStream, null);
userDatumWriter.write(obj, binaryEncoder);
return outputStream.toByteArray();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public <T> T deserialize(byte[] data, Class<T> clazz) {
try {
DatumReader userDatumReader = new SpecificDatumReader(clazz);
BinaryDecoder binaryDecoder = DecoderFactory.get().directBinaryDecoder(new ByteArrayInputStream(data), null);
return (T) userDatumReader.read(clazz.newInstance(), binaryDecoder);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
7 ThriftSerializer
/**
* @version V1.0
* @author: lin_shen
* @date: 2018/11/18
* @Description: Thrift序列化(只能序列化IDL产生的类)
*/
public class ThriftSerializer implements ISerializer {
@Override
public <T> byte[] serialize(T obj) {
try {
TSerializer serializer = new TSerializer(new TBinaryProtocol.Factory());
return serializer.serialize((TBase) obj);
} catch (TException e) {
throw new RuntimeException(e);
}
}
@Override
public <T> T deserialize(byte[] data, Class<T> clazz) {
try {
TBase o = (TBase) clazz.newInstance();
TDeserializer tDeserializer = new TDeserializer();
tDeserializer.deserialize(o, data);
return (T) o;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
8 ProtocolBufferSerializer
/**
* @version V1.0
* @author: lin_shen
* @date: 2018/11/18
* @Description: ProtocolBuffer序列化(只能序列化IDL产生的类)
*/
public class ProtocolBufferSerializer implements ISerializer {
@Override
public <T> byte[] serialize(T obj) {
try {
return (byte[]) MethodUtils.invokeMethod(obj, "toByteArray");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public <T> T deserialize(byte[] data, Class<T> cls) {
try {
Object o = MethodUtils.invokeStaticMethod(cls, "getDefaultInstance");
return (T) MethodUtils.invokeMethod(o, "parseFrom", new Object[]{data});
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}