作者:唐亚峰 | 出自:唐亚峰博客
在做
JAVA
开发的时候,接触最多的就是java.io.Serializable
,通过该接口生成序列化ID,然后就可以通过java.io.ObjectInput
与java.io.ObjectOutput
进行序列化与反序列化,无需考虑跨语言调用,对序列化性能要求不高的情况,使用默认的是最方便的,虽然存在弊端,但也能满足大部分的需要….
为了更好的掌握Netty
序列化相关知识,本章使用Netty
给我们提供的ObjectEncoder
与ObjectDecoder
对订单请求与应答消息进行序列化操作…
开发例程
- 在服务端ChannelPipeline新增解码器io.netty.handler.codec.serialization.ObjectDecoder
- 在服务端ChannelPipeline新增解码器io.netty.handler.codec.serialization.ObjectEncoder
- 实体类实现java.io.Serializable序列化接口
1、 创建OrderRequest
与OrderResponse
两个Java
类;
public class OrderRequest implements java.io.Serializable {
private static final long serialVersionUID = 1826067782744144943L;
private Integer orderId;
private String userName;
private String productName;
private String phoneNumber;
private String address;
//省略 get set ..
}
public class OrderResponse implements java.io.Serializable {
private static final long serialVersionUID = -5003946216600820264L;
private Integer orderId;
private String respCode;
private String desc;
}
OrderServer
1、 重写ChannelInitializer
中的initChannel
方法,添加ObjectDecoder
解码器与ObjectEncoder
编码器;
@Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline().addLast(new ObjectDecoder(1024 * 1024, ClassResolvers.weakCachingResolver(this.getClass().getClassLoader())));
channel.pipeline().addLast(new ObjectEncoder());
channel.pipeline().addLast(new OrderServerHandler());
}
注意 ObjectDecoder(int maxObjectSize, ClassResolver classResolver)
,第一个参数是设置序列化对象的最大字节长度,如果超出限定范围会抛出StreamCorruptedException
,默认(1024 * 1024 = 1048576字节),第二个参数用于做类解码
操作
2、 创建OrderServerHandler
,然后将接收到的消息做过滤,满足条件回写消息事件;
private static class OrderServerHandler extends ChannelHandlerAdapter {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
OrderRequest request = (OrderRequest) msg;
if ("Levin".equalsIgnoreCase(request.getUserName())) {//如果是Levin购买的,返回消息
System.out.println("Service Accept Client Order Request :[" + request.toString() + "]");
ctx.writeAndFlush(response(request.getOrderId()));
}
}
private OrderResponse response(Integer orderId) {
OrderResponse response = new OrderResponse();
response.setOrderId(orderId);
response.setRespCode("200");
response.setDesc("下单成功");
return response;
}
}
OrderClient
1、 创建OrderClientHandler
,请求3
次然后将数据写入缓冲区后调用flush
发送;
private static class OrderClientHandler extends ChannelHandlerAdapter {
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
for (int i = 1; i <= 3; i++) {
ctx.write(request(i));
}
ctx.flush();
}
private Object request(int i) {
OrderRequest request = new OrderRequest();
request.setAddress("上海市青浦区赵重公路1888号");
request.setOrderId(i);
request.setPhoneNumber("130XXXX1912");
request.setProductName("一起来学Netty");
request.setUserName("Levin");
return request;
}
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
System.out.println("Receive Server Response :[" + msg + "]");
}
}
试验一把
分别启动
OrderServer
和OrderClient
,将会看到如下日志
绑定端口,同步等待成功......
Service Accept Client Order Request :[OrderRequest{orderId=1, userName='Levin', productName='一起来学Netty', phoneNumber='130XXXX1912', address='上海市青浦区赵重公路1888号'}]
Service Accept Client Order Request :[OrderRequest{orderId=2, userName='Levin', productName='一起来学Netty', phoneNumber='130XXXX1912', address='上海市青浦区赵重公路1888号'}]
Service Accept Client Order Request :[OrderRequest{orderId=3, userName='Levin', productName='一起来学Netty', phoneNumber='130XXXX1912', address='上海市青浦区赵重公路1888号'}]
---------------------------------------------------------------------------------------------------------
Receive Server Response :[OrderResponse{orderId=1, respCode='200', desc='下单成功'}]
Receive Server Response :[OrderResponse{orderId=2, respCode='200', desc='下单成功'}]
Receive Server Response :[OrderResponse{orderId=3, respCode='200', desc='下单成功'}]
总结
本章介绍了如何利用Netty
提供的解码器与编码器实现对普通的对象进行序列化操作,通过订单案例可以发现Netty
为我们做了很多事情,短短几行代码就能完成序列化操作,我们只需关注自身业务即可,极大的提高了开发效率….
– 说点什么
全文代码:https://git.oschina.net/battcn/battcn-netty/tree/master/Chapter6-1/battcn-netty-6-1-1