• 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("收到的订单请求信息:\n"+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序列化的时候完全一样

序列化在Netty中的使用的更多相关文章

  1. Netty(五)序列化protobuf在netty中的使用

    protobuf是google序列化的工具,主要是把数据序列化成二进制的数据来传输用的.它主要优点如下: 1.性能好,效率高: 2.跨语言(java自带的序列化,不能跨语言) protobuf参考文档 ...

  2. Netty中的那些坑

    Netty中的那些坑(上篇) 最近开发了一个纯异步的redis客户端,算是比较深入的使用了一把netty.在使用过程中一边优化,一边解决各种坑.儿这些坑大部分基本上是Netty4对Netty3的改进部 ...

  3. Netty中的一些注意事项--底层基础

    转载自http://www.mamicode.com/info-detail-1215305.html 最近开发了一个纯异步的redis客户端,算是比较深入的使用了一把netty.在使用过程中一边优化 ...

  4. netty系列之:netty中的懒人编码解码器

    目录 简介 netty中的内置编码器 使用codec要注意的问题 netty内置的基本codec base64 bytes compression json marshalling protobuf ...

  5. 通过大量实战案例分解Netty中是如何解决拆包黏包问题的?

    TCP传输协议是基于数据流传输的,而基于流化的数据是没有界限的,当客户端向服务端发送数据时,可能会把一个完整的数据报文拆分成多个小报文进行发送,也可能将多个报文合并成一个大报文进行发送. 在这样的情况 ...

  6. 深度揭秘Netty中的FastThreadLocal为什么比ThreadLocal效率更高?

    阅读这篇文章之前,建议先阅读和这篇文章关联的内容. 1. 详细剖析分布式微服务架构下网络通信的底层实现原理(图解) 2. (年薪60W的技巧)工作了5年,你真的理解Netty以及为什么要用吗?(深度干 ...

  7. netty系列之:netty中常用的对象编码解码器

    目录 简介 什么是序列化 重构序列化对象 序列化不是加密 使用真正的加密 使用代理 Serializable和Externalizable的区别 netty中对象的传输 ObjectEncoder O ...

  8. 【转】Netty那点事(二)Netty中的buffer

    [原文]https://github.com/code4craft/netty-learning/blob/master/posts/ch2-buffer.md 上一篇文章我们概要介绍了Netty的原 ...

  9. Netty那点事: 概述, Netty中的buffer, Channel与Pipeline

    Netty那点事(一)概述 Netty和Mina是Java世界非常知名的通讯框架.它们都出自同一个作者,Mina诞生略早,属于Apache基金会,而Netty开始在Jboss名下,后来出来自立门户ne ...

随机推荐

  1. SharePoint 2010 文档管理系列之准备篇

    前言:很早自己就想写一个系列的文章,但是不知道写什么,最近在QQ群里,好多人说在做文档管理,其实文档管理也是SharePoint的一个很不错的功能点,自己想了想,也想多学习点东西,所以写这个主题吧,今 ...

  2. Android Java类编写规范+优化建议

    本文仅是我个人在实际开发中习惯的编写方式,当然这种方式也是来自很多官方的推荐,所以在一定程度上是可以被模仿套用的.本文将不定期更新~ 零.指导原则 优先保证可读性,不要过分追求代码艺术和效率 在可读性 ...

  3. 【读书笔记】iOS网络-HTTP-请求内容

    一,GET方法. 从服务器获取一段内容,用HTTP术语来说就是实体.GET请求通常不包含请求体,不过也是可以包含的.有些网络缓存设施只会缓存GET响应.GET请求通常不会导致服务器端的数据变化. 二, ...

  4. iOS 学习 - 7.限制 TextField 输入字符长度

    #pragma mark -- TextField代理 -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange: ...

  5. Ruby安装

    Windows下安装ruby 先安装ruby吧 点击安装,额,咳咳什么情况,好了 人是有国籍的,但知识无国界的 是这个意思吧,选择安装语言   选择安装目录 顺便勾选上添加到环境变量吧   安装完成 ...

  6. Windows 7 与 Vmware Ubuntu 15.10_64 共享文件夹

    设置共享文件夹     安装/更新最新的vmware-tools   安装             在ubuntu 内部会打开DVD ,里面的压缩包中包含vmware-toole. 先解压      ...

  7. 学习随笔—Redis常用命令

    info 服务器基本信息 monitor 实时转储收到的请求 flushdb 清空当前数据库 flushall 清空所有数据库 quit 关闭连接 save 将数据同步保持到磁盘 bgsave     ...

  8. SQL Server游标的使用【转】

    游标是邪恶的! 在关系数据库中,我们对于查询的思考是面向集合的.而游标打破了这一规则,游标使得我们思考方式变为逐行进行.对于类C的开发人员来着,这样的思考方式会更加舒服. 正常面向集合的思维方式是: ...

  9. 第一篇:微信公众平台开发实战Java版之了解微信公众平台基础知识以及资料准备

    相信很多人或多或少听说了微信公众平台的火热.但是开发还是有一点门槛,鉴于挺多朋友问我怎么开发,问多了,自己平时也进行以下总结.所以下面给大家分享一下我的经验: 微信公众号是什么? 官网的介绍:再小的个 ...

  10. shell读取文件每一行的方式

    1.使用read命令读取一行数据 while read myline do echo "LINE:"$myline done < datafile.txt 2.使用read命 ...