本文目录导读:

- 内置序列化(Java原生)
- JSON序列化(Jackson)
- Protocol Buffers(Protobuf)
- Avro序列化
- Kryo高性能序列化
- 分布式场景配置(Spring Boot + Redis)
- 性能对比与选择建议
- 最佳实践建议
在Java分布式系统中,数据格式化器(通常是序列化器)的选择直接影响系统的性能、跨语言兼容性和可维护性,以下是几种常见的序列化方案及其在分布式环境下的实现方式:
内置序列化(Java原生)
import java.io.*;
public class JavaNativeSerializer {
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
oos.writeObject(obj);
}
return bos.toByteArray();
}
public static Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
ByteArrayInputStream bis = new ByteArrayInputStream(data);
try (ObjectInputStream ois = new ObjectInputStream(bis)) {
return ois.readObject();
}
}
}
// 使用示例
@Data
@AllArgsConstructor
class User implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
private int age;
}
缺点:性能差、跨语言困难、不安全。
JSON序列化(Jackson)
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
public class JsonSerializer {
private static final ObjectMapper MAPPER = new ObjectMapper()
.registerModule(new JavaTimeModule())
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
public static byte[] serialize(Object obj) throws Exception {
return MAPPER.writeValueAsBytes(obj);
}
public static <T> T deserialize(byte[] data, Class<T> clazz) throws Exception {
return MAPPER.readValue(data, clazz);
}
}
Protocol Buffers(Protobuf)
// 1. 定义 .proto 文件
// user.proto
// syntax = "proto3";
// message User {
// string name = 1;
// int32 age = 2;
// }
// 2. 生成 Java 代码后使用
import com.google.protobuf.InvalidProtocolBufferException;
public class ProtobufSerializer {
public static byte[] serialize(UserProto.User user) {
return user.toByteArray();
}
public static UserProto.User deserialize(byte[] data) throws InvalidProtocolBufferException {
return UserProto.User.parseFrom(data);
}
}
Avro序列化
import org.apache.avro.Schema;
import org.apache.avro.generic.GenericData;
import org.apache.avro.generic.GenericRecord;
import org.apache.avro.io.*;
import org.apache.avro.specific.SpecificDatumWriter;
public class AvroSerializer {
private static final Schema SCHEMA;
static {
String schemaStr = "{\"type\":\"record\"," +
"\"name\":\"User\"," +
"\"fields\":[{\"name\":\"name\",\"type\":\"string\"}," +
"{\"name\":\"age\",\"type\":\"int\"}]}";
SCHEMA = new Schema.Parser().parse(schemaStr);
}
public static byte[] serialize(GenericRecord record) throws Exception {
DatumWriter<GenericRecord> writer = new SpecificDatumWriter<>(SCHEMA);
ByteArrayOutputStream out = new ByteArrayOutputStream();
BinaryEncoder encoder = EncoderFactory.get().binaryEncoder(out, null);
writer.write(record, encoder);
encoder.flush();
return out.toByteArray();
}
}
Kryo高性能序列化
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import com.esotericsoftware.kryo.serializers.JavaSerializer;
public class KryoSerializer {
private static final ThreadLocal<Kryo> KRYO_THREAD_LOCAL = ThreadLocal.withInitial(() -> {
Kryo kryo = new Kryo();
kryo.setDefaultSerializer(JavaSerializer.class);
kryo.register(User.class, 1);
return kryo;
});
public static byte[] serialize(Object obj) {
Kryo kryo = KRYO_THREAD_LOCAL.get();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
Output output = new Output(baos);
kryo.writeObject(output, obj);
output.close();
return baos.toByteArray();
}
public static <T> T deserialize(byte[] data, Class<T> clazz) {
Kryo kryo = KRYO_THREAD_LOCAL.get();
Input input = new Input(data);
return kryo.readObject(input, clazz);
}
}
分布式场景配置(Spring Boot + Redis)
@Configuration
public class SerializationConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(factory);
// 使用 Jackson2JsonRedisSerializer
Jackson2JsonRedisSerializer<Object> serializer =
new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.activateDefaultTyping(
LazyObjectMapper.DefaultTyping.NON_FINAL,
JsonTypeInfo.As.PROPERTY);
serializer.setObjectMapper(mapper);
template.setValueSerializer(serializer);
template.setKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}
性能对比与选择建议
| 序列化方式 | 数据大小 | 序列化速度 | 跨语言 | 易用性 | 推荐场景 |
|---|---|---|---|---|---|
| Java原生 | 大 | 慢 | 差 | 好 | 仅限Java单机 |
| JSON | 中 | 中 | 好 | 好 | 通用场景 |
| Protobuf | 小 | 快 | 好 | 中 | 高性能RPC |
| Avro | 小 | 快 | 好 | 中 | 数据存储 |
| Kryo | 最小 | 最快 | 差 | 好 | Java集群内部通信 |
最佳实践建议
- 内部微服务通信:推荐使用 Protobuf 或 Avro(高性能、Schema演进)
- 对外API:使用 JSON(通用性好、易于调试)
- Java集群内部:可使用 Kryo(极致性能)
- 缓存存储:推荐 JSON 或 Protobuf
- 消息队列:推荐 Protobuf 或 Avro
选择合适的序列化方案需要权衡:
- 性能要求
- 跨语言需求
- Schema演进策略
- 调试便利性
- 社区支持度