序列化工具类
序列化即将对象序列化为字节数组,反序列化就是将字节数组恢复成对象。
主要的目的是方便传输和存储。
序列化工具类:
public class SerializeUtil {
private static Map, Schema>> cachedSchema = new ConcurrentHashMap<>();
private static Objenesis objenesis = new ObjenesisStd(true);
/**
* jdk 序列化工具的序列化与反序列化
*
* @param object
* @return
* @throws IOException
*/
public static byte[] JDKObjectToBytes(Object object) throws IOException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutput objectOutput = new ObjectOutputStream(byteArrayOutputStream);
objectOutput.writeObject(object);
return byteArrayOutputStream.toByteArray();
}
public static T JDKBytesToObject(byte[] bytes, Class clazz) throws Exception {
ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(bytes));
Object object = objectInputStream.readObject();
return (T) object;
}
/**
* 使用fastjson实现序列化和反序列化
*
* @param object
* @return
*/
public static byte[] FastJsonObjectToBytes(Object object) {
byte[] bytes = JSON.toJSONBytes(object);
return bytes;
}
/**
* fastjosn反序列化时,class必须要有默认构造函数,否则报错
* @param bytes
* @param clazz
* @param
* @return
*/
public static T FastJsonBytesToObject(byte[] bytes, Class clazz) {
return (T) JSON.parseObject(bytes, clazz);
}
/**
* 使用protostuff序列化
* @param obj
* @param
* @return
*/
public static byte[] serialize(T obj) {
Class cls = (Class) obj.getClass();
LinkedBuffer buffer = LinkedBuffer.allocate(LinkedBuffer.DEFAULT_BUFFER_SIZE);
try {
Schema schema = getSchema(cls);
return ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
} finally {
buffer.clear();
}
}
public static T deserialize(byte[] data, Class cls) {
try {
T message = objenesis.newInstance(cls);
Schema schema = getSchema(cls);
ProtostuffIOUtil.mergeFrom(data, message, schema);
return message;
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
/**
* 缓存schema
* @param cls
* @param
* @return
*/
private static Schema getSchema(Class cls) {
Schema schema = (Schema) cachedSchema.get(cls);
if (schema == null) {
schema = RuntimeSchema.createFrom(cls);
if (schema != null) {
cachedSchema.put(cls, schema);
}
}
return schema;
}
}
此类分别包含jdk序列化、fastjson序列化、protobuf序列化三种序列化方式。
注意prostuff需要包含maven依赖:
org.objenesis
objenesis
2.6
io.protostuff
protostuff-core
1.4.0
io.protostuff
protostuff-runtime
1.4.0
com.alibaba
fastjson
1.2.31
使用
首先定义一个类用于测试,注意此类没有默认构造函数。
public class Monster implements Serializable{
Integer hp;
Integer mp;
String name;
Integer level;
public Monster(String name,Integer level){
this.name=name;
this.level=level;
}
//省略getter、setter、hashCode、equals...
}
测试类:
public class SerializeUtilTest {
Monster monster = new Monster("boss", 100);
Class clazz = Monster.class;
@Test
public void jdkSerializeTest() throws Exception {
byte[] bytes = SerializeUtil.JDKObjectToBytes(monster);
System.out.println(bytes.length);
Monster object = SerializeUtil.JDKBytesToObject(bytes,clazz);
Assert.assertEquals(object, monster);
}
@Test(expected = com.alibaba.fastjson.JSONException.class)
public void fastJsonSerializeTest(){
byte[] bytes = SerializeUtil.FastJsonObjectToBytes(monster);
System.out.println(bytes.length);
Monster object = SerializeUtil.FastJsonBytesToObject(bytes,clazz);
Assert.assertEquals(object, monster);
}
@Test
public void serialize(){
byte[] serialize = SerializeUtil.serialize(monster);
System.out.println(serialize.length);
Object deserialize = SerializeUtil.deserialize(serialize, clazz);
Assert.assertEquals(deserialize,monster);
}
}
输出分别为199、27、8。
可以看出jdk默认序列化方式的效率极低,protobuf效率和字节都非常高效。
特别注意:fastjson反序列化的对象必须要有默认构造函数,否则会报错。protostuff使用objenesis不需要默认构函数创建对象。但是json格式可读性好,性能也还可以,推荐性能不高的场景优先json格式,对性能要求高的场景使用protostuff。