1、序列化和反序列化定义
如果需要持久化Java
对象,比如把
Java
对象保存到磁盘、缓存或者在网络中传输都需要将对象进行序列化
序列化:将数据结构(xml , json或其他数据)或者是对象转换为二进制流的过程
反序列化:
将在序列化中转变为二进制字节流的对象
和数据结构还原为原来的结构
简单来说,序列化就是用户数据转换为二进制流;反序列化就是二进制流转换为用户数据
2、序列化协议对应于TCP/IP 4层中的哪一层?
- 应用层
- 传输层
- 网络层
- 网络接口层
OSI七层模型中表示层主要是对应用层的用户数据进行处理转换为二进制流,也就是二进制流转换为用户能看的懂的应用层数据。这里对应的就是序列化(用户数据转换为二进制流)和反序列化(二进制流转为用户数据)
3、常见的序列化协议
3.1 JDK序列化
serialVersionUID 有什么作用?
序列化号 serialVersionUID 属于版本控制的作用。反序列化时,会检查 serialVersionUID 是否和当前类的 serialVersionUID 一致。
如果serialVersionUID 不一致则会抛InvalidClassException 异常。
强烈推荐每个序列化类都手动指定其 serialVersionUID,如果不手动指定,那么编译器会动态生成默认的serialVersionUID。自己维护serialVersionUID能更好的管理序列化和被序列化的JavaBean
需要被序列化的协议类
package cn.boo.entity;
import lombok.Data;
import java.io.Serializable;
/**
* @author boo
* @date
* 不管etcd中存储的是对象还是json 我们最终都要转换为二进制数据
*/
@Data
public class RegisterEntity implements Serializable {
private static final long serialVersionUID = 1805122051950251255L;
private String serviceName;//服务名称
private int port;//端口
private String ip;//域名
}
3.2 使用Hessian和Kryo进行序列化
3.3 Hessian代码实现
Hessian是一个轻量级的
remoting onhttp
工具,使用简单的方法提供了RMI
的功能。
Hessian
更简单、快捷。
采用的是
二进制
RPC
协议,因为采用的是二进制协议,所以它很适合
于发送二进制数据。
添加依赖
<dependency>
<groupId>com.caucho</groupId>
<artifactId>hessian</artifactId>
<version>4.0.66</version>
</dependency>
代码实现
package cn.boo;
import cn.boo.entity.RegisterEntity;
import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
/**
* @author boo
* @date
*/
public class HessianTools {
private static Logger logger = LoggerFactory.getLogger(HessianTools.class);
public void hessianTool() throws Exception{
long startTime = System.currentTimeMillis();
RegisterEntity registerEntity = new RegisterEntity();
registerEntity.setIp("127.0.0.1");
registerEntity.setPort(8080);
//序列化
ByteArrayOutputStream os = new ByteArrayOutputStream();
Hessian2Output output = new Hessian2Output(os);
output.writeObject(registerEntity);
output.close();
byte[] bytes = os.toByteArray();
//反序列化
ByteArrayInputStream in = new ByteArrayInputStream(bytes);
Hessian2Input input = new Hessian2Input(in);
System.out.println(input.readObject());
input.close();
logger.info("耗时:"+ (System.currentTimeMillis() startTime)/1000.00);
}
public static void main(String[] args) {
HessianTools hessianTools = new HessianTools();
try {
hessianTools.hessianTool();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
hession序列化使用说明
1.
序列化对象要实现
Serializable
接口,
否则序列化时
会报
must implement java.io.Serializable
异常
2.
序列化对象不需要添加
serialVersionUID
,即使有serialVersionUID,修改了
serialVersionUID也
不影响反序列化
3. hessian
会把复杂对象所有属性存储在一个
Map
中进行序列化。所以在父类、子类存在同名成员变量的情况下, Hessian
序列化时,先序列化子类,然后序
列化父类,因此反序列化结果会导致子类同名成员变
量被父类的值覆盖
3.4 Kryo代码实现
Kryo 是一个快速高效的
Java
对象序列化框架,主要特点是性能、高效和易用。该项目用来序列化对象到文件、数据库或者网络
添加Maven依赖
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.5.0</version>
</dependency>
代码实现
package cn.boo;
import cn.boo.entity.RegisterEntity;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.util.Pool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* @author boo
* @date
*/
public class KryoSerializeUtil {
private static Logger logger = LoggerFactory.getLogger(KryoSerializeUtil.class);
public static final int BUFFER_SIZE = 2048;
public static final int MAX_BUFFER_SIZE = 10485760;
private static Pool<Kryo> kryoPool = null;
static{
/**
* 1. 参数详解:池构造函数参数:线程安全、软引用、最大容量 :
* public Pool(boolean threadSafe,boolean softReferences, final int
maximumCapacity)
* threadSafe: 这个参数是制定是否需要再POOL内部同步,如果设置为true,则可以被多个线程并发访问。
* softReferences: 这个参数是是否使用softReferences进行存储对象,如果设置为true,则Kryo 池将会使用java.lang.ref.SoftReference 来存储对象。这允许池中的对象在 JVM 的内存压力大时被垃圾回收。
*/
kryoPool = new Pool<Kryo>(true,false, 8) {
protected Kryo create() {
Kryo kryo = new Kryo();
// Kryo 配置
kryo.register(RegisterEntity.class);
return kryo;
}
};
}
public static byte[] serialize(Object) throws Exception{
Kryo kryo = null;
Output output = null;
try{
// 5.5.0已经移除了pool.borrow(); 方法替换使用obtain()
kryo = kryoPool.obtain();
output = new Output(BUFFER_SIZE, MAX_BUFFER_SIZE);
kryo.writeClassAndObject(output, t);
output.flush();
return output.toBytes();
}catch(Exception e){
logger.error("异常" , e);
throw e;
}finally{
// 5.5.0已经移除了
pool.release();方法替换使用free()
kryoPool.free(kryo);
if(output != null){
try {
output.close();
output = null;
} catch (Exception e) {
logger.error("异常" , e);
}
}
}
}
public static Object deserialize(byte[] bytes) throws Exception{
Kryo kryo = null;
Input input = null;
try{
kryo = kryoPool.obtain();
input = new Input(bytes);
Object t = kryo.readClassAndObject(input);
return t;
}catch(Exception e){
logger.error("异常" , e);
throw e;
}finally{
if(input != null){
try {
input.close();
input = null;
} catch (Exception e) {
logger.error("异常" , e);
}
}
}
}
public static void main(String[] args) throws Exception {
RegisterEntity registerEntity = new RegisterEntity();
registerEntity.setPort(9000);
registerEntity.setIp("127.0.0.1");
byte[] data = KryoSerializeUtil.serialize(registerEntity);
registerEntity = (RegisterEntity)KryoSerializeUtil.deserialize(data);
System.out.println(registerEntity.getIp());
}
}
欢迎大佬进行补充和指点!