zoukankan      html  css  js  c++  java
  • 序列化在Netty中的使用

    • Java序列化的缺点

    1、无法跨语言

      对于Java序列化后的字节数组,别的语言无法进行反序列化

    2、序列化后的码流过大

    3、序列化性能低

    • 使用JDK自带的序列化进行对象的传输

    被传输的,实现了序列化接口的POJO

    package org.zln.netty.five.part04.dto;
    
    import org.apache.commons.lang3.builder.ToStringBuilder;
    
    import java.io.Serializable;
    
    /**
     * 用户订购请求信息
     * Created by sherry on 16/11/7.
     */
    public class SubscribeReq implements Serializable{
    
        //序列化
        private static final long serialVersionUID = 1L;
    
        //订购编号
        private int subReqID;
        //用户名
        private String userName;
        //订购的产品名称
        private String productName;
        //订购者联系电话
        private String phoneName;
        //订购者家庭地址
        private String address;
    
        @Override
        public String toString() {
            return new ToStringBuilder(this)
                    .append("subReqID", subReqID)
                    .append("userName", userName)
                    .append("productName", productName)
                    .append("phoneName", phoneName)
                    .append("address", address)
                    .toString();
        }
    
        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 getPhoneName() {
            return phoneName;
        }
    
        public void setPhoneName(String phoneName) {
            this.phoneName = phoneName;
        }
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    SubscribeReq
    package org.zln.netty.five.part04.dto;
    
    import org.apache.commons.lang3.builder.ToStringBuilder;
    
    import java.io.Serializable;
    
    /**
     * 订单请求的响应信息
     * Created by sherry on 16/11/7.
     */
    public class SubscribeResp implements Serializable {
    
        //序列化
        private static final long serialVersionUID = 1L;
    
        //订购编号
        private int subReqID;
        //订购结果  0-未成功
        private int respCode;
        //可选的详细描述信息
        private String desc;
    
        @Override
        public String toString() {
            return new ToStringBuilder(this)
                    .append("subReqID", subReqID)
                    .append("respCode", respCode)
                    .append("desc", desc)
                    .toString();
        }
    
        public int getSubReqID() {
            return subReqID;
        }
    
        public void setSubReqID(int subReqID) {
            this.subReqID = subReqID;
        }
    
        public int getRespCode() {
            return respCode;
        }
    
        public void setRespCode(int respCode) {
            this.respCode = respCode;
        }
    
        public String getDesc() {
            return desc;
        }
    
        public void setDesc(String desc) {
            this.desc = desc;
        }
    }
    SubscribeResp

    服务端

    package org.zln.netty.five.part04.server;
    
    import io.netty.bootstrap.ServerBootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioServerSocketChannel;
    import io.netty.handler.logging.LogLevel;
    import io.netty.handler.logging.LoggingHandler;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    /**
     * Created by sherry on 16/11/5.
     */
    public class SubReqServer {
        /**
         * 服务端绑定端口号
         */
        private int PORT;
    
        public SubReqServer(int PORT) {
            this.PORT = PORT;
        }
    
        /**
         * 日志
         */
        private static Logger logger = LoggerFactory.getLogger(SubReqServer.class);
    
        public void bind() {
            /*
            NioEventLoopGroup是线程池组
            包含了一组NIO线程,专门用于网络事件的处理
            bossGroup:服务端,接收客户端连接
            workGroup:进行SocketChannel的网络读写
             */
            EventLoopGroup bossGroup = new NioEventLoopGroup();
            EventLoopGroup workGroup = new NioEventLoopGroup();
            try {
                /*
                ServerBootstrap:用于启动NIO服务的辅助类,目的是降低服务端的开发复杂度
                 */
                ServerBootstrap serverBootstrap = new ServerBootstrap();
                serverBootstrap.group(bossGroup, workGroup)
                        .channel(NioServerSocketChannel.class)
                        .option(ChannelOption.SO_BACKLOG, 1024)//配置TCP参数,能够设置很多,这里就只设置了backlog=1024,
                        .handler(new LoggingHandler(LogLevel.DEBUG))
                        .childHandler(new SubReqServerInitializer());//绑定I/O事件处理类
                logger.debug("绑定端口号:" + PORT + ",等待同步成功");
                /*
                bind:绑定端口
                sync:同步阻塞方法,等待绑定完成,完成后返回 ChannelFuture ,主要用于通知回调
                 */
                ChannelFuture channelFuture = serverBootstrap.bind(PORT).sync();
                logger.debug("等待服务端监听窗口关闭");
                /*
                 closeFuture().sync():为了阻塞,服务端链路关闭后才退出.也是一个同步阻塞方法
                 */
                channelFuture.channel().closeFuture().sync();
            } catch (InterruptedException e) {
                logger.error(e.getMessage(), e);
            } finally {
                logger.debug("优雅退出,释放线程池资源");
                bossGroup.shutdownGracefully();
                workGroup.shutdownGracefully();
            }
        }
    }
    SubReqServer
    package org.zln.netty.five.part04.server;
    
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.serialization.ClassResolvers;
    import io.netty.handler.codec.serialization.ObjectDecoder;
    import io.netty.handler.codec.serialization.ObjectEncoder;
    
    /**
     * Created by sherry on 16/11/5.
     */
    public class SubReqServerInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
    
            ChannelPipeline pipeline = socketChannel.pipeline();
    
            /*
            ObjectDecoder:对实现了Serializable接口的POJO进行解码,用于解码请求对象
            1024 * 1024:设置1M大小,为最大的单个对象的序列化后的字节长度
            ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())):对类加载器进行缓存,线程安全.支持多线程并发访问,当虚拟机内存不足时,释放缓存时的内存,防止内存泄漏
             */
            pipeline.addLast(new ObjectDecoder(1024 * 1024, ClassResolvers.weakCachingConcurrentResolver(this.getClass().getClassLoader())));
            /*
            ObjectEncoder:服务端在发送的时候,将对象进行编码操作
             */
            pipeline.addLast(new ObjectEncoder());
            pipeline.addLast(new SubReqServerHandler());
    
    
        }
    }
    SubReqServerInitializer
    package org.zln.netty.five.part04.server;
    
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.zln.netty.five.part03.SessionUtils;
    import org.zln.netty.five.part04.dto.SubscribeReq;
    import org.zln.netty.five.part04.dto.SubscribeResp;
    
    /**
     * Handler主要用于对网络事件进行读写操作,是真正的业务类
     * 通常只需要关注 channelRead 和 exceptionCaught 方法
     * Created by sherry on 16/11/5.
     */
    public class SubReqServerHandler extends ChannelHandlerAdapter {
    
        /**
         * 日志
         */
        private Logger logger = LoggerFactory.getLogger(SubReqServerHandler.class);
    
        private static int count = 0;
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            SubscribeReq subscribeReq = (SubscribeReq) msg;
            logger.debug("收到的订单请求信息:
    "+subscribeReq);
    
            //根据请求信息,设置响应信息
            SubscribeResp subscribeResp = getSubscribeResp(subscribeReq);
            ctx.writeAndFlush(subscribeResp);
    
    
        }
    
        private SubscribeResp getSubscribeResp(SubscribeReq subscribeReq) {
            SubscribeResp subscribeResp = new SubscribeResp();
            subscribeResp.setSubReqID(subscribeReq.getSubReqID());
            subscribeResp.setRespCode(subscribeReq.getSubReqID());
            subscribeResp.setDesc("你订购的是一双红皮鞋,三天后发货");
            return subscribeResp;
        }
    
    
        @Override
        public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
            //将消息发送队列中的消息写入到SocketChannel中发送给对方
            logger.debug("channelReadComplete");
            ctx.flush();
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            //发生异常时,关闭 ChannelHandlerContext,释放ChannelHandlerContext 相关的句柄等资源
            logger.error(cause.getMessage(),cause);
            ctx.close();
        }
    }
    SubReqServerHandler

    客户端

    package org.zln.netty.five.part04.client;
    
    import io.netty.bootstrap.Bootstrap;
    import io.netty.channel.ChannelFuture;
    import io.netty.channel.ChannelOption;
    import io.netty.channel.EventLoopGroup;
    import io.netty.channel.nio.NioEventLoopGroup;
    import io.netty.channel.socket.nio.NioSocketChannel;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.zln.netty.five.part03.EchoServer;
    
    /**
     * Created by sherry on 16/11/5.
     */
    public class SubReqClient {
        /**
         * 日志
         */
        private Logger logger = LoggerFactory.getLogger(EchoServer.class);
    
        private String HOST;
        private int PORT;
    
        public SubReqClient(String HOST, int PORT) {
            this.HOST = HOST;
            this.PORT = PORT;
        }
    
        public void connect(){
            //配置客户端NIO线程组
            EventLoopGroup eventLoopGroup = new NioEventLoopGroup();
            try {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.group(eventLoopGroup)
                        .channel(NioSocketChannel.class)
                        .option(ChannelOption.TCP_NODELAY,true)
                        .handler(new SubReqClientInitializer());
                //发起异步连接操作
                logger.debug("发起异步连接操作 - start");
                ChannelFuture channelFuture = bootstrap.connect(HOST,PORT).sync();
                logger.debug("发起异步连接操作 - end");
                //等待客户端链路关闭
                logger.debug("等待客户端链路关闭 - start");
                channelFuture.channel().closeFuture().sync();
                logger.debug("等待客户端链路关闭 - end");
            } catch (InterruptedException e) {
                logger.error(e.getMessage(),e);
            }finally {
                //优雅的关闭
                eventLoopGroup.shutdownGracefully();
            }
        }
    }
    SubReqClient
    package org.zln.netty.five.part04.client;
    
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import io.netty.handler.codec.serialization.ClassResolvers;
    import io.netty.handler.codec.serialization.ObjectDecoder;
    import io.netty.handler.codec.serialization.ObjectEncoder;
    
    /**
     * Created by sherry on 16/11/5.
     */
    public class SubReqClientInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
    
            ChannelPipeline pipeline = socketChannel.pipeline();
    
            //与服务端不同,这里禁止对类加载器进行缓存
            pipeline.addLast(new ObjectDecoder(1024, ClassResolvers.cacheDisabled(this.getClass().getClassLoader())));
            pipeline.addLast(new ObjectEncoder());
            pipeline.addLast(new SubReqClientHandler());
        }
    }
    SubReqClientInitializer
    package org.zln.netty.five.part04.client;
    
    import io.netty.channel.ChannelHandlerAdapter;
    import io.netty.channel.ChannelHandlerContext;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import org.zln.netty.five.part04.dto.SubscribeReq;
    import org.zln.netty.five.part04.dto.SubscribeResp;
    
    /**
     * Created by sherry on 16/11/5.
     */
    public class SubReqClientHandler extends ChannelHandlerAdapter {
    
        /**
         * 日志
         */
        private Logger logger = LoggerFactory.getLogger(SubReqClientHandler.class);
    
        private static int count = 0;
    
        @Override
        public void channelActive(ChannelHandlerContext ctx) throws Exception {
            logger.debug("客户端连接上了服务端");
    
            for (int i = 0; i < 10; i++) {
                SubscribeReq subscribeReq = getSubscribeReq(i);
                ctx.writeAndFlush(subscribeReq);
            }
    
        }
    
        private SubscribeReq getSubscribeReq(int i) {
            SubscribeReq subscribeReq = new SubscribeReq();
            subscribeReq.setSubReqID(i);
            subscribeReq.setUserName("张柳宁"+i);
            subscribeReq.setProductName("红皮鞋"+i);
            subscribeReq.setPhoneName("123"+i);
            subscribeReq.setAddress("地址"+i);
            return subscribeReq;
        }
    
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            SubscribeResp subscribeResp = (SubscribeResp) msg;
            logger.debug("这是收到的第 " + (++count) + " 笔响应 -- " + subscribeResp);
        }
    
        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            ctx.close();
        }
    }
    SubReqClientHandler
    • 使用Marshalling第三方jar进行序列化

    POJO不变

    工具类

    package org.zln.netty.five.part05.marshalling;
    
    import io.netty.handler.codec.marshalling.DefaultMarshallerProvider;
    import io.netty.handler.codec.marshalling.DefaultUnmarshallerProvider;
    import io.netty.handler.codec.marshalling.MarshallerProvider;
    import io.netty.handler.codec.marshalling.MarshallingDecoder;
    import io.netty.handler.codec.marshalling.MarshallingEncoder;
    import io.netty.handler.codec.marshalling.UnmarshallerProvider;
    
    import org.jboss.marshalling.MarshallerFactory;
    import org.jboss.marshalling.Marshalling;
    import org.jboss.marshalling.MarshallingConfiguration;
    
    public class MarshallingCodeCFactory {
        public static MarshallingDecoder buildMarshallingDecoder() {
            /*
             * 通过 Marshalling 工具类的 getProvidedMarshallerFactory
             * 静态方法获取MarshallerFactory 实例, , 参数 serial 表示创建的是 Java 序列化工厂对象.它是由
             * jboss-marshalling-serial 包提供
             */
            final MarshallerFactory marshallerFactory = Marshalling
                    .getProvidedMarshallerFactory("serial");
            /*
             * 创建
             */
            final MarshallingConfiguration configuration = new MarshallingConfiguration();
            configuration.setVersion(5);
    
            UnmarshallerProvider provider = new DefaultUnmarshallerProvider(
                    marshallerFactory, configuration);
            /*
             * provider : 提供商 maxSize : 单个对象最大尺寸
             */
            int maxSize = 1024 << 2;
            MarshallingDecoder decoder = new MarshallingDecoder(provider, maxSize);
            return decoder;
        }
    
        public static MarshallingEncoder buildMarshallingEncoder() {
            final MarshallerFactory marshallerFactory = Marshalling
                    .getProvidedMarshallerFactory("serial");
            final MarshallingConfiguration configuration = new MarshallingConfiguration();
            configuration.setVersion(5);
            MarshallerProvider provider = new DefaultMarshallerProvider(
                    marshallerFactory, configuration);
            MarshallingEncoder decoder = new MarshallingEncoder(provider);
            return decoder;
        }
    
    }
    MarshallingCodeCFactory

    服务端

    package org.zln.netty.five.part05.server;
    
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import org.zln.netty.five.part05.marshalling.MarshallingCodeCFactory;
    
    /**
     * Created by sherry on 16/11/5.
     */
    public class SubReqServerInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
    
            ChannelPipeline pipeline = socketChannel.pipeline();
    
            //解码器
            pipeline.addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
            //编码器
            pipeline.addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
            pipeline.addLast(new SubReqServerHandler());
    
    
        }
    }

    客户端

    package org.zln.netty.five.part05.client;
    
    import io.netty.channel.ChannelInitializer;
    import io.netty.channel.ChannelPipeline;
    import io.netty.channel.socket.SocketChannel;
    import org.zln.netty.five.part05.marshalling.MarshallingCodeCFactory;
    
    /**
     * Created by sherry on 16/11/5.
     */
    public class SubReqClientInitializer extends ChannelInitializer<SocketChannel> {
        @Override
        protected void initChannel(SocketChannel socketChannel) throws Exception {
    
            ChannelPipeline pipeline = socketChannel.pipeline();
    
            //解码器
            pipeline.addLast(MarshallingCodeCFactory.buildMarshallingDecoder());
            //编码器
            pipeline.addLast(MarshallingCodeCFactory.buildMarshallingEncoder());
            pipeline.addLast(new SubReqClientHandler());
        }
    }

    其他代码和使用JDK序列化的时候完全一样

  • 相关阅读:
    图片验证码, 登录, 注销, 修改密码
    注册页面及注册功能实现
    高级配置文件, csrf, django settings源码, django auth模块, 文件配置的插拔式设计
    cookie操作, session操作, django中间件
    半自动创建多对多关系表, forms组件
    sweetalert, bulk_create, 分页器
    orm查询优化, MVC与MTV, choices参数, ajax
    聚合查询, 分组查询, F与Q查询, 常见字段及参数, 自定义Char字段, 事务操作
    Contest2058
    ACM版《孔乙己》
  • 原文地址:https://www.cnblogs.com/sherrykid/p/6036659.html
Copyright © 2011-2022 走看看