• 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. js验证真实姓名与身份证号,手机号

    最近的项目中用的需要调用实名认证的接口,实名认证接口价格相比短信而言高了不是几分钱,所以说调用实名认证的条件就要严格把关,因此用到js验证真实姓名与js验证身份证号. 进入正题 1.js验证真实姓名 ...

  2. dict和set

    #dict和set #dict #Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map #使用键-值(key-value)存储,具有极快的查找速度. #字 ...

  3. 在Mac上配置Android adb命令

    一 adb定义: adb(android debug bridge)是android系统中的一种命令行工具,通过它可以和android设备或模拟器通信. 二 在Mac上的配置过程 启动终端 进入当前用 ...

  4. 【转】IOS开发中图片资源使用png还是jpg格式

    对于iOS本地应用程序来说最简单的答案就是始终使用PNG,除非你有非常非常好的理由不用它. 当iOS应用构建的时候,Xcode会通过一种方式优化.png文件而不会优化其它文件格式.它优化得相当的好 他 ...

  5. UI界面的一些简单控件

    虽然都是代码 , 但是基本都有注释. #import "ViewController.h" @interface ViewController () /** * 创建视图 */ @ ...

  6. 关于Assets.car素材问题

    最近在做自己的第一个App,由于全程都是自己一个人完成,所以原型设计.素材都得自己找,自己改.遇到了提取Assets.car中的素材的问题,通过网络找到了2中解决方法: themeEngine 使 用 ...

  7. dd 生成指定大小文件

    d命令可以轻易实现创建指定大小的文件,如 dd if=/dev/zero of=test bs=1M count=1000 会生成一个1000M的test文件,文件内容为全0(因从/dev/zero中 ...

  8. Effective Java 14 In public classes, use accessor methods, not public fields

    Principle To offer the benefits of encapsulation you should always expose private field with public ...

  9. Effective Java 61 Throw exceptions appropriate to the abstraction

    Exception translation: higher layers should catch lower-level exceptions and, in their place, throw ...

  10. ECharts 之一——入门

    一.简介 ECharts是一个来自百度的开源的javascript图标库.通过ECharts我们可以呈现出多种类型的图表.ECharts底层基于ZRender(一个全新的轻量级canvas类库),创建 ...