protostuff基于protobuf的序列化/反序列化,不需要编写.proto文件,方便使用。
针对kryo的序列化demo,使用protostuff。在producer和consumer的配置中分别配置自定义的ProtostuffSerializer和ProtostuffDerializer即可
注意使用protostuff序列化需要注意,序列化和反序列化的字段顺序问题。
1、引入依赖
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-runtime</artifactId>
<version>1.5.9</version>
</dependency>
<dependency>
<groupId>io.protostuff</groupId>
<artifactId>protostuff-core</artifactId>
<version>1.5.9</version>
</dependency>
2、序列化反序列化工具
package org.example.learn2.util;
import io.protostuff.LinkedBuffer;
import io.protostuff.ProtostuffIOUtil;
import io.protostuff.Schema;
import io.protostuff.runtime.RuntimeSchema;
import org.objenesis.Objenesis;
import org.objenesis.ObjenesisStd;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* @author maochao
* @since 2019/7/8 18:00
*/
public class ProtostuffUtil {
private static final Objenesis objenesis = new ObjenesisStd(true);
private static final ConcurrentMap<Class<?>, Schema<?>> schemaCache = new ConcurrentHashMap<>();
private static ThreadLocal<LinkedBuffer> bufferThreadLocal = ThreadLocal.withInitial(() -> LinkedBuffer.allocate());
public static <T> byte[] serialize(T obj) {
Schema<T> schema = getSchema((Class<T>)obj.getClass());
// 默认分配512
LinkedBuffer buf = bufferThreadLocal.get();
try {
// object->byte[]
return ProtostuffIOUtil.toByteArray(obj, schema, buf);
} finally {
buf.clear();
}
}
private static<T> Schema<T> getSchema(Class<T> clazz) {
//缓存,
Schema<T> schema = (Schema<T>)schemaCache.get(clazz);
if (schema == null) {
// 把可序列化的字段封装到Schema
Schema<T> newSchema = RuntimeSchema.createFrom(clazz);
schema = (Schema<T>)schemaCache.putIfAbsent(clazz, newSchema);
if (schema == null) {
schema = newSchema;
}
}
return schema;
}
public static <T> T deserialize(byte[] bytes, Class<T> clazz) {
// clazz-->Object
T object = objenesis.newInstance(clazz);
Schema<T> schema = getSchema(clazz);
ProtostuffIOUtil.mergeFrom(bytes, object, schema);
return object;
}
}
3、重建消息对象
package org.example.learn2.entity;
import com.esotericsoftware.kryo.DefaultSerializer;
import java.io.Serializable;
import java.util.List;
/**
* 消息对象
*
* @author
* @date 2019/6/15
*/
public class KafkaMessage implements Serializable {
private String id;
// 消息对象
private Message message;
// .....其他属性
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
public class Message implements Serializable {
public Long getValue() {
return value;
}
public void setValue(Long value) {
this.value = value;
}
private Long value;
// ....其他属性
}
public Message builder() {
return new Message();
}
}
4、序列化
package org.example.learn2.producer;
import org.apache.kafka.common.serialization.Serializer;
import org.example.learn2.util.ProtostuffUtil;
import java.util.Map;
/**
*
* ProtostuffSerializer 编码器
*
* @author maochao
* @since 2019/7/8 17:58
*
*/
public class ProtostuffSerializer implements Serializer {
@Override
public void configure(Map configs, boolean isKey) {
}
@Override
public byte[] serialize(String topic, Object data) {
return ProtostuffUtil.serialize(data);
}
@Override
public void close() {
}
}
5、反序列化
package org.example.learn2.consumer;
import org.apache.kafka.common.serialization.Deserializer;
import org.example.learn2.entity.KafkaMessage;
import org.example.learn2.util.ProtostuffUtil;
import java.util.Map;
/**
* @author maochao
* @since 2019/7/8 19:29
*/
public class ProtostuffDerializer implements Deserializer {
@Override
public void configure(Map configs, boolean isKey) {
}
@Override
public Object deserialize(String topic, byte[] data) {
return ProtostuffUtil.deserialize(data, KafkaMessage.class);
}
@Override
public void close() {
}
}