netty 自定义序列化
使用示例
fastjson序列化、反序列化对象
Person
@Data
public class Person {
private String name;
private Integer age;
}
Product
@Data
public class Product {
private String name;
private Float price;
private Integer num;
}
***********
编解码器
CustomJsonEncoder
public class CustomJsonEncoder extends MessageToByteEncoder<Message> {
@Override
protected void encode(ChannelHandlerContext channelHandlerContext, Message message, ByteBuf byteBuf) throws Exception {
int startIndex = byteBuf.writerIndex();
byteBuf.writeInt(0);
byteBuf.writeBytes(message.getClassName().getBytes(StandardCharsets.UTF_8));
byteBuf.setInt(startIndex, byteBuf.writerIndex() - startIndex - 4);
int bodyIndex = byteBuf.writerIndex();
byteBuf.writeInt(0);
byteBuf.writeBytes(JSON.toJSONBytes(message.getInstance()));
byteBuf.setInt(bodyIndex, byteBuf.writerIndex() - bodyIndex -4);
}
}
CustomsonDecoder
public class CustomJsonDecoder extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext channelHandlerContext, ByteBuf byteBuf, List<Object> list) throws Exception {
int classLength = byteBuf.readInt();
byte[] className = new byte[classLength];
byteBuf.readBytes(className);
String name = new String(className);
int bodyLength = byteBuf.readInt();
byte[] instance = new byte[bodyLength];
byteBuf.readBytes(instance);
try {
Class<?> clz = Class.forName(name);
list.add(JSON.parseObject(instance,clz));
}catch (Exception e){
e.printStackTrace();
}
}
}
***********
服务端
CustomServerHandler
public class CustomServerHandler extends SimpleChannelInboundHandler<Object> {
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, Object object) throws Exception {
System.out.println("读取到json数据:" + object);
}
}
NettyServer
public class NettyServer {
public static void startServer(int port){
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap serverBootstrap = new ServerBootstrap();
serverBootstrap.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(new CustomJsonDecoder());
channelPipeline.addLast(new CustomJsonEncoder());
channelPipeline.addLast(new CustomServerHandler());
}
});
ChannelFuture channelFuture = serverBootstrap.bind(port).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
startServer(8000);
}
}
***********
客户端
CustomClientHandler
public class CustomClientHandler extends ChannelInboundHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
Message message = new Message();
message.setClassName(Person.class.getName());
Person person = new Person();
person.setName("瓜田李下");
person.setAge(20);
message.setInstance(person);
System.out.println(message);
ctx.channel().writeAndFlush(message);
Message message2 = new Message();
message2.setClassName(Product.class.getName());
Product product = new Product();
product.setName("苹果");
product.setPrice(10f);
product.setNum(10);
message2.setInstance(product);
ctx.channel().writeAndFlush(message2);
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("客户端读取的响应数据:"+msg);
}
}
NettyClient
public class NettyClient {
public static void connect(String host, int port){
EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
try {
Bootstrap bootstrap = new Bootstrap();
bootstrap.group(eventLoopGroup)
.channel(NioSocketChannel.class)
.option(ChannelOption.SO_KEEPALIVE, true)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel socketChannel) throws Exception {
ChannelPipeline channelPipeline = socketChannel.pipeline();
channelPipeline.addLast(new CustomJsonEncoder());
channelPipeline.addLast(new CustomJsonDecoder());
channelPipeline.addLast(new CustomClientHandler());
}
});
ChannelFuture channelFuture = bootstrap.connect(host,port).sync();
channelFuture.channel().closeFuture().sync();
}catch (Exception e){
e.printStackTrace();
}finally {
eventLoopGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
String host = "localhost";
int port = 8000;
connect(host, port);
}
}
***********
使用测试
点击运行后,服务端输出:
12:38:20.772 [main] DEBUG io.netty.buffer.ByteBufUtil - -Dio.netty.maxThreadLocalCharBufferSize: 16384
12:38:23.409 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.maxCapacityPerThread: 4096
12:38:23.409 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.ratio: 8
12:38:23.409 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.chunkSize: 32
12:38:23.409 [nioEventLoopGroup-3-1] DEBUG io.netty.util.Recycler - -Dio.netty.recycler.blocking: false
12:38:23.416 [nioEventLoopGroup-3-1] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkAccessible: true
12:38:23.416 [nioEventLoopGroup-3-1] DEBUG io.netty.buffer.AbstractByteBuf - -Dio.netty.buffer.checkBounds: true
12:38:23.419 [nioEventLoopGroup-3-1] DEBUG io.netty.util.ResourceLeakDetectorFactory - Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@4ff5a067
读取到json数据:Person(name=瓜田李下, age=20)
读取到json数据:Product(name=苹果, price=10.0, num=10)