Step01:定义mail类:
package com.java.serializable;
import java.io.Serializable;
import java.util.Date;
public class Mail implements Serializable{
private static final long serialVersionUID = 6599166688654530165L;
private Integer id;
private String title;
private String content;
private Date createdTime;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Date getCreatedTime() {
return createdTime;
}
public void setCreatedTime(Date createdTime) {
this.createdTime = createdTime;
}
@Override
public String toString() {
return "Mail [id=" + id + ", title=" + title + ", content=" + content + ", createdTime=" + createdTime + "]";
}
}
Step02:添加依赖
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.0.0-RC4</version>
</dependency>
Step03:编写测试类
package com.java.serializable;
import java.util.Date;
import org.apache.tomcat.util.http.fileupload.ByteArrayOutputStream;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
public class TestSerializable06 {
public static void main(String[] args) {
Mail m=new Mail();
m.setId(100);
m.setTitle("test");
m.setContent("this is test content");
m.setCreatedTime(new Date());
//基于Kryo框架将对象序列化
Kryo kryo=new Kryo();
//将默认类的自动注册功能关闭(默认会将类全名序列化)
kryo.setRegistrationRequired(false);
//kryo.register(Mail.class);
//kryo.register(Date.class);
ByteArrayOutputStream bos=//内置可扩容数组
new ByteArrayOutputStream();
Output output=new Output(bos);
kryo.writeObject(output, m); //写入null时会报错
output.close();
System.out.println("序列化ok");
//基于Kryo框架将对象反序列化
byte[] data=bos.toByteArray();
Input input=new Input(data);
Mail m2=kryo.readObject(input,Mail.class); //读出null时会报错
input.close();
System.out.println(m2);
}
}
结果:
序列化ok
Mail [id=100, title=test, content=this is test content, createdTime=Mon Nov 11 14:15:35 CST 2019]
可将如上序列化方法进行封装,写到序列化工具类中,例如:
public class KryoSerializer {
private static final ThreadLocal<Kryo> kryoLocal = ThreadLocal.withInitial(() -> {
Kryo kryo = new Kryo();
kryo.setReferences(true);//检测循环依赖,默认值为true,避免版本变化显式设置
kryo.setRegistrationRequired(false);//默认值为true,避免版本变化显式设置
((DefaultInstantiatorStrategy) kryo.getInstantiatorStrategy())
.setFallbackInstantiatorStrategy(new StdInstantiatorStrategy());//设定默认的实例化器
return kryo;
});
public byte[] serialize(Object obj) {
Kryo kryo = getKryo();
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
Output output = new Output(byteArrayOutputStream);
kryo.writeClassAndObject(output, obj);
output.close();
return byteArrayOutputStream.toByteArray();
}
public <T> T deserialize(byte[] bytes) {
Kryo kryo = getKryo();
Input input = new Input(new ByteArrayInputStream(bytes));
return (T) kryo.readClassAndObject(input);
}
private Kryo getKryo() {
return kryoLocal.get();
}
}
编写测试类:
package com.java.serializable;
import java.io.IOException;
import java.util.Date;
public class TestSerializable07 {
public static void main(String[] args)throws IOException {
Mail m=new Mail();
m.setId(100);
m.setTitle("test");
m.setContent("this is test content");
m.setCreatedTime(new Date());
//基于Kryo框架将对象序列化
byte[] array=
KryoSerializer.serializable(m);
System.out.println("序列化OK,array.length="+array.length);
//基于Kryo框架将对象反序列化
Mail m2=
KryoSerializer.deserialization(array,Mail.class);
System.out.println(m2);
}
}
运行结果:
序列化OK,array.length=49
Mail [id=100, title=test, content=this is test content, createdTime=Mon Nov 11 18:04:03 CST 2019]
根据是否写入class类型分为两种方式, 这里特别指出这里的的class指的是读写对象的class, 如果读写的是有嵌套类型对象,则不管采用哪种方式, 子类型class都会序列化.
kryo.writeObject(output, someObject);
// ...
SomeClass someObject = kryo.readObject(input, SomeClass.class);
kryo.writeObjectOrNull(output, someObject);
// ...
SomeClass someObject = kryo.readObjectOrNull(input, SomeClass.class);
class未知且对象可能为null, 但这种场景, 会多占用空间. 这种方式是我们在RPC中应当使用的方式
kryo.writeClassAndObject(output, object);
// ...
Object object = kryo.readClassAndObject(input);
if (object instanceof SomeClass) {
// ...
}
register
kryo支持通过类注册, 注册会给每一个class一个int类型的Id相关联,这显然比类名称高效,但同时要求反序列化的时候的Id必须与序列化过程中一致。这意味着注册的顺序非常重要。
kryo.register(SomeClassA.class);
kryo.register(SomeClassB.class);
但是由于现实原因,同样的代码,同样的Class在不同的机器上注册编号任然不能保证一致,所以多机器部署时候反序列化可能会出现问题。
所以kryo默认会开启类注册(version:5.0.2),可以通过kryo.setRegistrationRequired(false)关闭, 关闭后Kryo会根据类型去loadClass关联
kryo.setRegistrationRequired(false);//一般设置为false
由于Kryo线程不安全, 意味着每次序列化和反序列化时都需要实例化一次, 或借助ThreadLocal来维护以保证其线程安全。
private static final ThreadLocal<Kryo> kryos = new ThreadLocal<Kryo>() {
protected Kryo initialValue() {
Kryo kryo = new Kryo();
// configure kryo instance, customize settings
return kryo;
};
};
// Somewhere else, use Kryo
Kryo k = kryos.get();
...
或者使用kryo提供的pool:
public KryoPool newKryoPool() {
return new KryoPool.Builder(() -> {
final Kryo kryo = new Kryo();
kryo.setInstantiatorStrategy(new Kryo.DefaultInstantiatorStrategy(
new StdInstantiatorStrategy()));
return kryo;
}).softReferences().build();
}