Netty的java序列化实现
一.java序列化开发
1.1 服务端的开发
1.1.1 使用netty对POJO对象进行序列化
package serializable;
import java.io.Serializable;
/*
* 对POJO对象进行序列化 ,订购请求POJO
*/
public class SubscribeReq implementsSerializable{
privatestatic final long serialVersionUID=1L;
privateint subReqID;
privateString userName;
privateString productName;
privateString phoneNumber;
privateString address;
publicint getSubReqID() {
returnsubReqID;
}
publicvoid setSubReqID(int subReqID) {
this.subReqID= subReqID;
}
publicString getUserName() {
returnuserName;
}
publicvoid setUserName(String userName) {
this.userName= userName;
}
publicString getProductName() {
returnproductName;
}
publicvoid setProductName(String productName) {
this.productName= productName;
}
publicString getPhoneNumber() {
returnphoneNumber;
}
publicvoid setPhoneNumber(String phoneNumber) {
this.phoneNumber= phoneNumber;
}
publicString getAddress() {
returnaddress;
}
publicvoid setAddress(String address) {
this.address= address;
}
publicstatic long getSerialversionuid() {
returnserialVersionUID;
}
@Override
publicString toString(){
return"Subscribereq[subReqID="+subReqID+",userName="+userName+",productName="+productName+",phoneNumber="+phoneNumber+",address="+address+"]";
}
}
1.1.2 订购应答POJO
package serializable;
import java.io.Serializable;
/*
* 订购应答POJO
*/
public class SubscribeResp implementsSerializable{
private static final long serialVersionUID=1L;
private int subReqID;
private int respCode;
private String desc;
public int getSubReqID() {
returnsubReqID;
}
public void setSubReqID(int subReqID) {
this.subReqID= subReqID;
}
public int getRespCode() {
returnrespCode;
}
public void setRespCode(int respCode) {
this.respCode= respCode;
}
public String getDesc() {
returndesc;
}
public void setDesc(String desc) {
this.desc= desc;
}
public static long getSerialversionuid() {
returnserialVersionUID;
}
@Override
public String toString(){
return "SubscribeResp [subReqID="+subReqID+",respCode="+respCode+",desc="+desc+"]";
}
}
1.1.3 订购服务端
package serializable;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
importio.netty.channel.nio.NioEventLoopGroup;
importio.netty.channel.socket.SocketChannel;
importio.netty.channel.socket.nio.NioServerSocketChannel;
importio.netty.handler.codec.DelimiterBasedFrameDecoder;
importio.netty.handler.codec.FixedLengthFrameDecoder;
importio.netty.handler.codec.LineBasedFrameDecoder;
importio.netty.handler.codec.serialization.ClassResolvers;
import io.netty.handler.codec.serialization.ObjectDecoder;
importio.netty.handler.codec.serialization.ObjectEncoder;
importio.netty.handler.codec.string.StringDecoder;
import io.netty.handler.logging.LogLevel;
importio.netty.handler.logging.LoggingHandler;
/*
* 订购服务端
*/
public class SubReqServer {
publicvoid bind(int port) throws Exception{
//配置服务端的NIO线程组
EventLoopGroupbossGroup =new NioEventLoopGroup();
EventLoopGroupworkerGroup =new NioEventLoopGroup();
try{
//用于启动NIO服务器的辅助启动类,降低服务端的开发复杂度
ServerBootstrapb=new ServerBootstrap();
b.group(bossGroup,workerGroup).
channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,100)
.handler(newLoggingHandler(LogLevel.INFO))
.childHandler(newChannelInitializer<SocketChannel>() {
@Override
publicvoid initChannel(SocketChannel ch) throws Exception{
// 使用weakCachingConcurrentResolver创建线程安全的weakreferenceMap对类加载器进行缓存
//它支持多线程并发访问,当虚拟机内存不足,会释放缓存中的内存,防止内存泄漏
//这里设置为1M,在例程中足够使用
ch.pipeline().addLast(
newObjectDecoder(
1024*1024,
ClassResolvers
.weakCachingConcurrentResolver(this.getClass().getClassLoader())));
//在消息发送的时候自动将实现Serializable的POJO对象进行解码,
//因此用户无须亲自对对象进行手工序列化,只需要关注自己的业务逻辑处理即可,
//对象序列化和反序列化都由Netty对象解编码器完成
ch.pipeline().addLast(newObjectEncoder());
//将订购处理handler SubReqServerHandler添加到ChannelPipeline的尾部用于业务逻辑处理
ch.pipeline().addLast(newSubReqServerHandler());
}
});
//绑定端口,同步等待成功
ChannelFuturef=b.bind(port).sync();
//等待服务端监听端口关闭
f.channel().closeFuture().sync();
}catch (Exception e) {
//TODO: handle exception
}finally{
//优雅退出,释放线程池资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
publicstatic void main(String[] args) throws Exception{
intport=8080;
if(args!=null&&args.length>0){
try{
port=Integer.valueOf(args[0]);
}catch (NumberFormatException e) {
//TODO: handle exception
}
}
newSubReqServer().bind(port);
}
}
1.1.4 订购服务处理类
package serializable;
importio.netty.channel.ChannelHandlerAdapter;
import io.netty.channel.ChannelHandlerContext;
/*
* 订购服务处理
*/
public class SubReqServerHandler extendsChannelHandlerAdapter{
@Override
public void channelRead(ChannelHandlerContext ctx,Object msg) throwsException{
SubscribeReq req=(SubscribeReq) msg;
// 对订购者的用户名进行合法性校验,校验通过后打印订购请求消息,
// 构造订购成功应答消息立即发送给客户端
if("zhengguang".equalsIgnoreCase(req.getUserName())){
System.out.println("Serviceaccept client subscribe req : ["+req.toString()+"]");
ctx.writeAndFlush(resp(req.getSubReqID()));
}
}
private SubscribeResp resp(int subReqID){
SubscribeResp resp=new SubscribeResp();
resp.setSubReqID(subReqID);
resp.setRespCode(0);
resp.setDesc("Netty book ordersucceed,3 days later"
+ ",sent to thedesignated address");
return resp;
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
cause.printStackTrace();
ctx.close(); // 发生异常,关闭链路
}
}
2.1 客户端开发
2.1.1 产品订购客户端
package serializable;
import client.TimeClient;
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
importio.netty.channel.nio.NioEventLoopGroup;
importio.netty.channel.socket.SocketChannel;
importio.netty.channel.socket.nio.NioSocketChannel;
importio.netty.handler.codec.serialization.ClassResolvers;
importio.netty.handler.codec.serialization.ObjectDecoder;
importio.netty.handler.codec.serialization.ObjectEncoder;
/*
* 产品订购服务端
*/
public class SubReqClient {
publicvoid connect(int port,String host) throws Exception{
//配置客户端NIO线程组
EventLoopGroupgroup =new NioEventLoopGroup();
try{
Bootstrapb=new Bootstrap();
b.group(group).channel(NioSocketChannel.class)
.option(ChannelOption.TCP_NODELAY,true)
.handler(newChannelInitializer<SocketChannel>() {
@Override
publicvoid initChannel(SocketChannel ch) throws Exception{
ch.pipeline().addLast(
newObjectDecoder(1024,ClassResolvers
.cacheDisabled(this.getClass()
.getClassLoader())));
ch.pipeline().addLast(newObjectEncoder());
ch.pipeline().addLast(newSubReqClientHandler());
}
});
//发起异步连接操作
ChannelFuturef=b.connect(host,port).sync();
// 等待客户端链路关闭
f.channel().closeFuture().sync();
}catch (Exception e) {
//TODO: handle exception
}finally{
group.shutdownGracefully();
}
}
publicstatic void main(String[] args) throws Exception{
intport=8080;
if(args!=null&&args.length>0){
try{
port=Integer.valueOf(args[0]);
}catch (NumberFormatException e) {
//TODO: handle exception
}
newSubReqClient().connect(port,"127.0.0.1");
}
}
}
2.1.3 SubReqClientHandler实现
package serializable;
importio.netty.channel.ChannelHandlerAdapter;
importio.netty.channel.ChannelHandlerContext;
public class SubReqClientHandler extendsChannelHandlerAdapter{
publicSubReqClientHandler(){
}
publicvoid channelActive(ChannelHandlerContext ctx){
//在链路激活的时候循环构造10条订购请求消息,最后一次性的发送给服务端
for(inti=0;i<10;i++){
ctx.write(subReq(i));
}
ctx.flush();
}
privateSubscribeReq subReq(int i){
SubscribeReqreq=new SubscribeReq();
req.setAddress("上海市");
req.setPhoneNumber("13311111111");
req.setProductName("书籍");
req.setSubReqID(i);
req.setUserName("zhenggaung");
returnreq;
}
@Override
publicvoid channelRead(ChannelHandlerContext ctx,Object msg) throws Exception{
System.out.println("Receiveserver response:["+msg+"]");
}
@Override
publicvoid channelReadComplete(ChannelHandlerContext ctx) throws Exception{
ctx.flush();
}
@Override
publicvoid exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
cause.printStackTrace();
ctx.close();
}
}