Netty 权威指南之java 序列化

符号 阅读:584 2021-03-31 22:28:38 评论:0

本章相关知识点:

相信大多数的程序员接触到的第一种序列化或者编码技术是Java序列化,需要实现序列化的POJO对象只需要实现java.io.serlizable接口,根据实际情况生成序列ID,这个类就能通过java.io.ObjectInput 和java.io.ObjectOutput序列化和反序列化。

不需要考虑跨语言调用,对序列化性能没有苛刻的要求,Java默认写序列化机制是最好的选择,真因为如此,Java序列化虽然存在很多弊端,但是依然得到广泛的运用。


本章学习要点:

1、Netty java 序列化服务端开发

2、Netty Java序列化客户端开发

3、运行结果


第一节:Netty java 序列化服务端开发

服务端开发情景如下:Netty服务端接受到客户端的用户订购请求信息,消息定义如图下表7-1


服务端接受到请求信息,对客户合法性进行校验。如果合法,则构造订购成功的应答消息返回个客户端。订购应答消息如表7-2


Netty 服务端开发步骤:

1、在服务端ChannelPipline中新增解码器io.netty.handler.codec.serialization.ObjectDecoder

2、在服务端ChannelPipline 中新增解码器io.netty.handler.codec.serialization.ObjectEncoder

3、需要进行java 序列化的POJO对象必须实现java.io.serializable接口。

服务端代码

SubRespServer.java 

package com.nio.server; 
 
import com.nio.handler.SubRespServerHandler; 
import io.netty.bootstrap.ServerBootstrap; 
import io.netty.channel.ChannelFuture; 
import io.netty.channel.ChannelInitializer; 
import io.netty.channel.ChannelOption; 
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; 
 
/** 
 * Created by vixuan-008 on 2015/6/23. 
 */ 
public class SubRespServer { 
    public static void main(String[] args)throws Exception{ 
        int port=15444; 
        new SubRespServer().bind(port); 
    } 
 
    public void bind(int port)throws Exception{ 
        //配置服务端的NIO线程池 
        EventLoopGroup bossGroup=new NioEventLoopGroup(); 
        EventLoopGroup workGroup=new NioEventLoopGroup(); 
        try{ 
            ServerBootstrap b=new ServerBootstrap(); 
            b.group(bossGroup, workGroup); 
            b.channel(NioServerSocketChannel.class); 
            b.option(ChannelOption.SO_BACKLOG, 100); 
            b.childHandler(new ChannelInitializer<SocketChannel>() { 
                @Override 
                protected void initChannel(SocketChannel socketChannel) throws Exception { 
                    socketChannel.pipeline().addLast(new ObjectDecoder(1024*1024, ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader()))); 
                    socketChannel.pipeline().addLast(new ObjectEncoder()); 
                    socketChannel.pipeline().addLast(new SubRespServerHandler()); 
 
                } 
            }); 
            //绑定端口,等待同步成功 
            ChannelFuture f=b.bind(port).sync(); 
            //等待服务端关闭监听端口 
            f.channel().closeFuture().sync(); 
 
        }finally { 
            //释放线程池资源 
            bossGroup.shutdownGracefully(); 
            workGroup.shutdownGracefully(); 
 
        } 
 
 
    } 
} 

SubRespServerHandler.java

package com.nio.handler; 
 
import com.nio.serlizable.SubscribeReq; 
import com.nio.serlizable.SubscribeResp; 
import io.netty.channel.ChannelHandlerAdapter; 
import io.netty.channel.ChannelHandlerContext; 
 
/** 
 * Created by vixuan-008 on 2015/6/23. 
 */ 
public class SubRespServerHandler extends ChannelHandlerAdapter { 
    @Override 
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
        SubscribeReq subscribeReq=(SubscribeReq)msg; 
        if(subscribeReq.getUserName().equalsIgnoreCase("zhouzhigang")){ 
           System.out.println("server rceiver dats is:" + subscribeReq.toString()+"") ; 
            ctx.writeAndFlush(resp(subscribeReq.getSubReqId())); 
        } 
    } 
 
    @Override 
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 
        ctx.close(); 
    } 
 
    private SubscribeResp resp(int subReqId){ 
        SubscribeResp resp=new SubscribeResp(); 
        resp.setDesc("Netty Book order success,3 day later ,send to the designated address"); 
        resp.setRespCode("0"); 
        resp.setSubReqId(subReqId); 
        return  resp; 
 
    } 
} 

第二节:Netty Java序列化客户端开发

SubReqClient.java

package com.nio.client; 
 
import com.nio.handler.SubReqServerHandler; 
import io.netty.channel.ChannelFuture; 
import io.netty.channel.ChannelInitializer; 
import io.netty.channel.ChannelOption; 
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; 
 
/** 
 * Created by vixuan-008 on 2015/6/23. 
 */ 
public class SubReqClient { 
    public static void main(String[] args)throws Exception{ 
        int port=15444; 
        new SubReqClient().bind(port, "127.0.0.1"); 
    } 
    public void bind(int port,String host)throws Exception{ 
        //配置客户端NIO线程池 
        EventLoopGroup workGroup=new NioEventLoopGroup(); 
        try{ 
            io.netty.bootstrap.Bootstrap b=new io.netty.bootstrap.Bootstrap(); 
            b.group(workGroup); 
            b.channel(NioSocketChannel.class); 
            b.option(ChannelOption.TCP_NODELAY,true); 
            b.handler(new ChannelInitializer<SocketChannel>() { 
                @Override 
                protected void initChannel(SocketChannel socketChannel) throws Exception { 
 
                    socketChannel.pipeline().addLast(new ObjectDecoder(1024, ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader()))); 
                    socketChannel.pipeline().addLast(new ObjectEncoder()); 
                    socketChannel.pipeline().addLast(new SubReqServerHandler()); 
                } 
            }); 
            //发起异步连接操作 
            ChannelFuture f=b.connect(host,port).sync(); 
            //等待客户端链路关闭 
            f.channel().closeFuture().sync(); 
 
        }finally { 
            //释放NIO 线程组 
            workGroup.shutdownGracefully(); 
 
        } 
 
 
    } 
} 

SubReqServerHandler.java

package com.nio.handler; 
 
import com.nio.serlizable.SubscribeReq; 
import io.netty.channel.ChannelHandlerAdapter; 
import io.netty.channel.ChannelHandlerContext; 
 
/** 
 * Created by vixuan-008 on 2015/6/23. 
 */ 
public class SubReqServerHandler extends ChannelHandlerAdapter { 
    @Override 
    public void channelActive(ChannelHandlerContext ctx) throws Exception { 
      for(int i=0;i<10;i++){ 
          ctx.write(subReq(i)); 
      } 
        ctx.flush(); 
    } 
 
    public SubscribeReq subReq(int i){ 
        SubscribeReq req=new SubscribeReq(); 
        req.setAddress("湖南长沙雨花区西子一间"); 
        req.setPhoneNumber("1877498****"); 
        req.setUserName("zhouzhigang"); 
        req.setSubReqId(i); 
        req.setProductName("java 开发指南"); 
        return req; 
    } 
 
    @Override 
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 
        System.out.println("Receiver message is:"+msg); 
    } 
 
    @Override 
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { 
       ctx.close(); 
    } 
 
    @Override 
    public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { 
       ctx.flush(); 
    } 
} 

相关实体类POJO补充:

SubscribeReq.java

package com.nio.serlizable; 
 
/** 
 * Created by vixuan-008 on 2015/6/23. 
 */ 
public class SubscribeReq implements java.io.Serializable { 
    private static final long serialVersionUID=1L; 
 
    private int subReqId; 
    private String userName; 
    private String productName; 
    private String phoneNumber; 
    private String address; 
 
    public int getSubReqId() { 
        return subReqId; 
    } 
 
    public void setSubReqId(int subReqId) { 
        this.subReqId = subReqId; 
    } 
 
    public String getUserName() { 
        return userName; 
    } 
 
    public void setUserName(String userName) { 
        this.userName = userName; 
    } 
 
    public String getProductName() { 
        return productName; 
    } 
 
    public void setProductName(String productName) { 
        this.productName = productName; 
    } 
 
    public String getPhoneNumber() { 
        return phoneNumber; 
    } 
 
    public void setPhoneNumber(String phoneNumber) { 
        this.phoneNumber = phoneNumber; 
    } 
 
    public String getAddress() { 
        return address; 
    } 
 
    public void setAddress(String address) { 
        this.address = address; 
    } 
 
    @Override 
    public String toString() { 
        return "SubscribeReq:{subReqId:"+subReqId+",userName:"+userName+",productName:"+productName+",phoneNumber:"+phoneNumber+",address:"+address+"}"; 
    } 
} 

SubscribeResp.java

package com.nio.serlizable; 
 
/** 
 * Created by vixuan-008 on 2015/6/23. 
 */ 
public class SubscribeResp implements java.io.Serializable { 
    private static final long serialVersionUID=1L; 
 
    private int subReqId; 
    private String respCode; 
    private String desc; 
 
    public int getSubReqId() { 
        return subReqId; 
    } 
 
    public void setSubReqId(int subReqId) { 
        this.subReqId = subReqId; 
    } 
 
    public String getRespCode() { 
        return respCode; 
    } 
 
    public void setRespCode(String respCode) { 
        this.respCode = respCode; 
    } 
 
    public String getDesc() { 
        return desc; 
    } 
 
    public void setDesc(String desc) { 
        this.desc = desc; 
    } 
 
    @Override 
    public String toString() { 
        return "SubscribeResp:{subReqId:"+subReqId+",respCode:"+respCode+",desc:"+desc+"}"; 
    } 
} 

第三节:运行结果

服务端截图:


客户端截图:



总结:本章节重点介绍如何使用Netty 提供的ObjectEncoed编码器和ObjectDecode 解码器实现对普通POJO的序列化。通过订书Demo,我们学习了服务端和客户端的开发,并且模拟TCP的粘包和拆包场景,对运行结果进行了相关分析。

通过使用Netty的Java序列化编解码handler,用户通过短短的几行代码,就能完成POJO的序列化和反序列化。在业务处理handler中,用户只需要将精力聚焦业务逻辑的实现上,不需要关心底层代码的实现,这极大的提高开发效率。

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

关注我们

一个IT知识分享的公众号