Netty支持多种序列化和反序列化机制,包括Java原生的序列化机制、Google的Protocol Buffers、JSON、XML等。下面将详细介绍如何在Netty中实现序列化和反序列化,并结合代码示例进行说明。
Java原生序列化
Java原生序列化机制可以使用 ObjectEncoder 和 ObjectDecoder 来实现。
示例:使用Java原生序列化机制
- 定义一个可序列化的对象:
java
import java.io.Serializable;
public class MyMessage implements Serializable {
private static final long serialVersionUID = 1L;
private String content;
public MyMessage(String content) {
this.content = content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "MyMessage{" +
"content='" + content + '\'' +
'}';
}
}
- 服务器端实现:
java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
public class SerializationServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new ObjectEncoder());
p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
p.addLast(new SerializationServerHandler());
}
});
b.bind(8080).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class SerializationServerHandler extends SimpleChannelInboundHandler<MyMessage> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyMessage msg) throws Exception {
System.out.println("Server received: " + msg);
ctx.writeAndFlush(new MyMessage("Hello from server!"));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
- 客户端实现:
java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
import io.netty.handler.codec.serialization.ObjectEncoder;
public class SerializationClient {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new ObjectEncoder());
p.addLast(new ObjectDecoder(ClassResolvers.cacheDisabled(null)));
p.addLast(new SerializationClientHandler());
}
});
b.connect("localhost", 8080).sync().channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class SerializationClientHandler extends SimpleChannelInboundHandler<MyMessage> {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(new MyMessage("Hello from client!"));
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyMessage msg) throws Exception {
System.out.println("Client received: " + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
使用Protocol Buffers
Protocol Buffers(Protobuf)是一种灵活、高效、自动化的序列化机制,适用于语言无关、平台无关的数据交换格式。以下是使用Protobuf的示例。
示例:使用Protobuf进行序列化和反序列化
- 定义Protobuf消息:
创建一个 message.proto 文件:
protobuf
syntax = "proto3";
option java_package = "com.example.protobuf";
option java_outer_classname = "MessageProtos";
message MyMessage {
string content = 1;
}
- 生成Java类:
使用 protoc 编译 message.proto 文件:
sh
protoc --java_out=. message.proto
- 服务器端实现:
java
import com.example.protobuf.MessageProtos.MyMessage;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
public class ProtobufServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new ProtobufVarint32FrameDecoder());
p.addLast(new ProtobufDecoder(MyMessage.getDefaultInstance()));
p.addLast(new ProtobufVarint32LengthFieldPrepender());
p.addLast(new ProtobufEncoder());
p.addLast(new ProtobufServerHandler());
}
});
b.bind(8080).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
import com.example.protobuf.MessageProtos.MyMessage;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class ProtobufServerHandler extends SimpleChannelInboundHandler<MyMessage> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyMessage msg) throws Exception {
System.out.println("Server received: " + msg.getContent());
MyMessage response = MyMessage.newBuilder().setContent("Hello from server!").build();
ctx.writeAndFlush(response);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
- 客户端实现:
java
import com.example.protobuf.MessageProtos.MyMessage;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.protobuf.ProtobufDecoder;
import io.netty.handler.codec.protobuf.ProtobufEncoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32FrameDecoder;
import io.netty.handler.codec.protobuf.ProtobufVarint32LengthFieldPrepender;
public class ProtobufClient {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new ProtobufVarint32FrameDecoder());
p.addLast(new ProtobufDecoder(MyMessage.getDefaultInstance()));
p.addLast(new ProtobufVarint32LengthFieldPrepender());
p.addLast(new ProtobufEncoder());
p.addLast(new ProtobufClientHandler());
}
});
b.connect("localhost", 8080).sync().channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
import com.example.protobuf.MessageProtos.MyMessage;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class ProtobufClientHandler extends SimpleChannelInboundHandler<MyMessage> {
@Override
public void channelActive(ChannelHandlerContext ctx) {
MyMessage message = MyMessage.newBuilder().setContent("Hello from client!").build();
ctx.writeAndFlush(message);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyMessage msg) throws Exception {
System.out.println("Client received: " + msg.getContent());
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
使用JSON
Netty也支持使用JSON进行序列化和反序列化。
示例:使用JSON进行序列化和反序列化
- 添加依赖:
在 pom.xml 中添加 Jackson 的依赖:
xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.13.0</version>
</dependency>
- 定义消息对象:
java
public class MyMessage {
private String content;
public MyMessage() {
}
public MyMessage(String content) {
this.content = content;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
@Override
public String toString() {
return "MyMessage{" +
"content='" + content + '\'' +
'}';
}
}
- 自定义编解码器:
java
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.MessageToByteEncoder;
public class JsonEncoder extends MessageToByteEncoder<Object> {
private final ObjectMapper objectMapper = new ObjectMapper();
@Override
protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
byte[] bytes = objectMapper.writeValueAsBytes(msg);
out.writeBytes(bytes);
}
}
import com.fasterxml.jackson.databind.ObjectMapper;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import java.util.List;
public class JsonDecoder<T> extends ByteToMessageDecoder {
private final ObjectMapper objectMapper = new ObjectMapper();
private final Class<T> clazz;
public JsonDecoder(Class<T> clazz) {
this.clazz = clazz;
}
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
byte[] bytes = new byte[in.readableBytes()];
in.readBytes(bytes);
T obj = objectMapper.readValue(bytes, clazz);
out.add(obj);
}
}
- 服务器端实现:
java
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
public class JsonServer {
public static void main(String[] args) throws Exception {
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new JsonDecoder<>(MyMessage.class));
p.addLast(new JsonEncoder());
p.addLast(new JsonServerHandler());
}
});
b.bind(8080).sync().channel().closeFuture().sync();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class JsonServerHandler extends SimpleChannelInboundHandler<MyMessage> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyMessage msg) throws Exception {
System.out.println("Server received: " + msg);
ctx.writeAndFlush(new MyMessage("Hello from server!"));
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
- 客户端实现:
java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
public class JsonClient {
public static void main(String[] args) throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline p = ch.pipeline();
p.addLast(new JsonDecoder<>(MyMessage.class));
p.addLast(new JsonEncoder());
p.addLast(new JsonClientHandler());
}
});
b.connect("localhost", 8080).sync().channel().closeFuture().sync();
} finally {
group.shutdownGracefully();
}
}
}
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
public class JsonClientHandler extends SimpleChannelInboundHandler<MyMessage> {
@Override
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(new MyMessage("Hello from client!"));
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, MyMessage msg) throws Exception {
System.out.println("Client received: " + msg);
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
ctx.close();
}
}
通过以上示例,您可以了解如何在Netty中使用Java原生序列化、Protocol Buffers和JSON进行序列化和反序列化。选择哪种方式取决于您的具体需求和环境。