本文已参与「新人创作礼」活动,一起开启掘金创作之路。
示例代码的公共接口
该篇文章接上篇 序列化实际场景对比
public interface KvSerializer {
/**
* 将对象序列化为 byte 数组
*
* @param object 序列化的对象
* @return
*/
byte[] serialize(Object object) throws Throwable;
/**
* 将 byte 数组序列化为指定类型
*
* @param bytes byte 数组
* @param clazz 类型
* @param <T> 泛型 T,和 clazz 类型一致
* @return
*/
<T> T deserialize(byte[] bytes, Class<T> clazz) throws Throwable;
}
序列化使用代码示例
Kryo
官方文档:
中文:blog.csdn.net/fanjunjaden…
英文:github.com/EsotericSof…
- Kryo序列化机制比默认的Java序列化机制速度要快,序列化后的数据要更小,大概是Java序列化机制的1/10。所以Kryo序列化优化以后,可以让网络传输的数据变少,在集群中耗费的内存资源大大减少
- 使用kryo默认的序列化方式fieldSerializer, 对需要序列化的对象采取默认的操作。开启reference,关闭register
- Kryo在类注册且reference关闭的情况下,序列化速度和大小明显 优于hessian和java,接近于protostuff。开启reference后将序列化速度将明显变慢,但仍旧优于hessian
- 目前只有java实现,不能用于在多个系统、多种语言间的数据交换
- 依赖
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>4.0.2</version>
</dependency>
- Kryo 序列化示例代码
public class KryoKvSerializer implements KvSerializer {
private Logger log = LoggerFactory.getLogger(KryoKvSerializer.class);
private static final ThreadLocal<Kryo> KRYO_THREAD_LOCAL = new ThreadLocal<Kryo>() {
@Override
protected Kryo initialValue() {
Kryo kryo = new Kryo();
/**
* 不要轻易改变这里的配置,更改之后,序列化的格式就会发生变化,
* 上线的同时就必须清除 Redis 里的所有缓存,
* 否则那些缓存再回来反序列化的时候,就会报错
*/
//支持对象循环引用(否则会栈溢出)
kryo.setReferences(true); //默认值就是 true,添加此行的目的是为了提醒维护者,不要改变这个配置
//不强制要求注册类(注册行为无法保证多个 JVM 内同一个类的注册编号相同;而且业务系统中大量的 Class 也难以一一注册)
kryo.setRegistrationRequired(false); //默认值就是 false,添加此行的目的是为了提醒维护者,不要改变这个配置
//Fix the NPE bug when deserializing Collections.
((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy())
.setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
return kryo;
}
};
private static KryoFactory factory = new KryoFactory() {
@Override
public Kryo create() {
Kryo kryo = new Kryo();
/**
* 不要轻易改变这里的配置!更改之后,序列化的格式就会发生变化,
* 上线的同时就必须清除 Redis 里的所有缓存,
* 否则那些缓存再回来反序列化的时候,就会报错
*/
//支持对象循环引用(否则会栈溢出)
kryo.setReferences(true); //默认值就是 true,添加此行的目的是为了提醒维护者,不要改变这个配置
//不强制要求注册类(注册行为无法保证多个 JVM 内同一个类的注册编号相同;而且业务系统中大量的 Class 也难以一一注册)
kryo.setRegistrationRequired(false); //默认值就是 false,添加此行的目的是为了提醒维护者,不要改变这个配置
//Fix the NPE bug when deserializing Collections.
((Kryo.DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy())
.setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());
return kryo;
}
};
private static KryoPool pool = new KryoPool.Builder(factory).softReferences().build();
@Override
public byte[] serialize(Object object) throws Throwable {
if (object == null) {
return null;
}
Kryo kryo = KRYO_THREAD_LOCAL.get();
byte[] bytes = null;
try {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Output output = new Output(byteArrayOutputStream);
kryo.writeClassAndObject(output, object);
output.flush();
output.close();
bytes = byteArrayOutputStream.toByteArray();
} catch (Exception e) {
log.error("Kryo 序列化对象异常,异常信息为: {}", e);
throw e;
} finally {
return bytes;
}
}
@Override
public <T> T deserialize(byte[] bytes, Class<T> clazz) throws Throwable {
if (bytes == null) {
return null;
}
Kryo kryo = pool.borrow();
T object = null;
try {
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
Input input = new Input(byteArrayInputStream);
object = (T) kryo.readClassAndObject(input);
input.close();
} catch (Exception e) {
log.error("Kryo 反序列化对象异常,异常信息为: {}", e);
throw e;
} finally {
pool.release(kryo);
return object;
}
}
}
protostuff
是google在原来的protobuffer是的优化产品。使用起来也比较简单易用,目前效率也是最好的一种序列化工具
- 依赖
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.4.0</version>
</dependency>
- Protostuff 序列化示例代码
public class ProtostuffKvSerializer implements KvSerializer {
private Logger log = LoggerFactory.getLogger(ProtostuffKvSerializer.class);
private static Objenesis objenesis = new ObjenesisStd(true);
private static Map<Class<?>, Schema<?>> cachedSchema = new ConcurrentHashMap();
private static <T> Schema<T> getSchema(Class<T> cls) {
Schema<T> schema = (Schema)cachedSchema.get(cls);
if (schema == null) {
schema = RuntimeSchema.createFrom(cls);
if (schema != null) {
cachedSchema.put(cls, schema);
}
}
return (Schema)schema;
}
@Override
public byte[] serialize(Object obj) {
Class cls = obj.getClass();
LinkedBuffer buffer = LinkedBuffer.allocate(512);
byte[] bytes;
try {
Schema schema = getSchema(cls);
bytes = ProtostuffIOUtil.toByteArray(obj, schema, buffer);
} catch (Exception e) {
log.error("Protostuff 序列化对象异常,异常信息为: {}", e);
throw e;
} finally {
buffer.clear();
}
return bytes;
}
@Override
public <T> Object deserialize(byte[] bytes, Class<T> clazz) {
try {
T message = objenesis.newInstance(clazz);
Schema<T> schema = getSchema(clazz);
ProtostuffIOUtil.mergeFrom(bytes, message, schema);
return message;
} catch (Exception e) {
log.error("Protostuff 反序列化对象异常,异常信息为: {}", e);
throw e;
}
}
}
JDK
- JDK 序列化示例代码
public class JdkKvSerializer implements KvSerializer {
private Logger log = LoggerFactory.getLogger(JdkKvSerializer.class);
@Override
public byte[] serialize(Object object) throws Throwable {
if (object == null) {
return null;
}
byte[] bytes = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(object);
oos.flush();
bytes = bos.toByteArray();
oos.close();
bos.close();
} catch (IOException e) {
log.error("JDK 序列化对象异常,异常信息为: {}", e);
throw e;
}
return bytes;
}
@Override
public <T> T deserialize(byte[] bytes, Class<T> clazz) throws Throwable {
if (bytes == null) {
return null;
}
Object obj = null;
try {
ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bis);
obj = ois.readObject();
ois.close();
bis.close();
} catch (Exception e) {
log.error("JDK 反序列化对象异常,异常信息为: {}", e);
throw e;
}
return (T) obj;
}
}
Hessian(Hessian1)
- 依赖
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.62</version>
</dependency>
- Hessian 序列化示例代码
public class Hessian1KvSerializer implements KvSerializer {
private Logger log = LoggerFactory.getLogger(Hessian1KvSerializer.class);
public byte[] serialize(Object obj) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
HessianOutput ho = new HessianOutput(os);
byte[] bytes;
try {
ho.writeObject(obj);
ho.flush();
byte[] result = os.toByteArray();
bytes = result;
} catch (IOException e) {
log.error("Hessian1 序列化对象异常,异常信息为: {}", e);
throw e;
} finally {
try {
ho.close();
os.close();
} catch (IOException e) {
log.error("Hessian1 序列化对象异常,异常信息为: {}", e);
throw e;
}
}
return bytes;
}
public <T> Object deserialize(byte[] bytes, Class<T> clazz) {
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
HessianInput hi = new HessianInput(is);
Object obj;
try {
Object result = hi.readObject();
obj = result;
} catch (IOException e) {
log.error("Hessian1 反序列化对象异常,异常信息为: {}", e);
throw e;
} finally {
try {
hi.close();
is.close();
} catch (Exception e) {
log.error("Hessian1 反序列化对象异常,异常信息为: {}", e);
throw e;
}
}
return obj;
}
}
Hessian(Hessian2)
- 依赖
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.62</version>
</dependency>
- Hessian 序列化示例代码
public class Hessian2KvSerializer implements KvSerializer {
private Logger log = LoggerFactory.getLogger(Hessian2KvSerializer.class);
public byte[] serialize(Object obj) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
Hessian2Output ho = new Hessian2Output(os);
byte[] bytes;
try {
ho.writeObject(obj);
ho.flush();
byte[] result = os.toByteArray();
bytes = result;
} catch (Exception e) {
log.error("Hessian2 序列化对象异常,异常信息为: {}", e);
throw e;
} finally {
try {
ho.close();
os.close();
} catch (IOException e) {
log.error("Hessian2 序列化对象异常,异常信息为: {}", e);
throw e;
}
}
return bytes;
}
public <T> Object deserialize(byte[] bytes, Class<T> clazz) {
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
Hessian2Input hi = new Hessian2Input(is);
Object obj;
try {
Object result = hi.readObject();
obj = result;
} catch (IOException e) {
log.error("Hessian2 反序列化对象异常,异常信息为: {}", e);
throw e;
} finally {
try {
hi.close();
is.close();
} catch (IOException e) {
log.error("Hessian2 反序列化对象异常,异常信息为: {}", e);
throw e;
}
}
return obj;
}
}
Jackson
- 依赖
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9.1</version>
</dependency>
- Jackson 序列化示例代码
public class JacksonKvSerializer implements KvSerializer {
private Logger log = LoggerFactory.getLogger(Hessian2KvSerializer.class);
private static final ObjectMapper objectMapper = new ObjectMapper();
public JacksonSerializer() {
}
public <T> byte[] serialize(T obj) {
try {
return objectMapper.writeValueAsBytes(obj);
} catch (Exception e) {
log.error("Jackson 序列化对象异常,异常信息为: {}", e);
throw e;
}
}
public <T> Object deserialize(byte[] bytes, Class<T> clazz) {
try {
return objectMapper.readValue(bytes, clazz);
} catch (Exception e) {
log.error("Jackson 反序列化对象异常,异常信息为: {}", e);
throw e;
}
}
}