序列化就是将一个对象的状态(各个属性量)保存起来,然后在适当的时候再获得。
序列化分为两大部分:序列化和反序列化。序列化是这个过程的第一部分,将数据分解成字节流,以便存储在文件中或在网络上传输。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。恢复数据要求有恢复数据的对象实例
序列化的作用
- 把对象的字节序列永久地保存到硬盘上(通常存放在一个文件中);
- 在网络上传送对象的字节序列。
当你想把的内存中的对象保存到一个文件中或者数据库中时候;
当你想用套接字在网络上传送对象的时候;
当你想通过RMI传输对象的时候;
Serializable接口
public class Message implements Serializable{
private static final long serialVersionUID = 1L;
private long id; //id
private long receiveId; //接受者
private long sendId; //发送者
private String content; //内容
private int type; //类型
private int state; //状态
private Date createTime; //创建时间
/**
* @return the id
*/
public long getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(long id) {
this.id = id;
}
/**
* @return the receive
*/
public long getReceiveId() {
return receiveId;
}
/**
* @param receive the receive to set
*/
public void setReceiveId(long receiveId) {
this.receiveId = receiveId;
}
/**
* @return the send
*/
public long getSendId() {
return sendId;
}
/**
* @param send the send to set
*/
public void setSendId(long sendId) {
this.sendId = sendId;
}
/**
* @return the content
*/
public String getContent() {
return content;
}
/**
* @param content the content to set
*/
public void setContent(String content) {
this.content = content;
}
/**
* @return the type
*/
public int getType() {
return type;
}
/**
* @param type the type to set
*/
public void setType(int type) {
this.type = type;
}
/**
* @return the state
*/
public int getState() {
return state;
}
/**
* @param state the state to set
*/
public void setState(int state) {
this.state = state;
}
/**
* @return the createTime
*/
public Date getCreateTime() {
return createTime;
}
/**
* @param createTime the createTime to set
*/
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public String toString() {
return "message [id=" + id + ", receiveId=" + receiveId + ", sendId=" + sendId + ", content="+ content
+ ", type=" + type + ", state=" + state + ", createTime=" + createTime + "]";
}
}
Protobuf
简述
Protocol Buffers (ProtocolBuffer/ protobuf )是Google公司开发的一种数据描述语言,类似于XML能够将结构化数据序列化,可用于数据存储、通信协议等方面。现阶段支持C++、JAVA、Python等三种编程语言。
- 结构化数据存储方式(XML、 JSON)
- 高效的编解码性能
- 语言无关、平台无关、扩展性好
- 官方支持JAVA、C++、Python三种语言
使用过程:
完整示例 : http://download.csdn.net/detail/hq0556/9826665
1. 选择版本下载protobuf : https://github.com/google/protobuf/releases;
2. 项目加入protobuf-java.jar包;
3. 编写xxx.proto;
4. cmd进入protoc.exe文件夹下:protoc.exe –java_out=./ xxx.proto
示例
<dependency> <groupId>com.google.protobuf</groupId> <artifactId>protobuf-java</artifactId> <version>2.5.0</version> </dependency>
编写message.proto,与上例Message类对应
package com.heqing.netty.bean.protobuf; option java_package = "com.heqing.netty.bean.protobuf"; option java_outer_classname = "ProtobufProto"; message testBuf { required int64 id = 1; required int64 receiveId = 2; required int64 sendId = 3; required string content= 4; required int32 type = 5; required int32 state = 6; required int64 createTime = 7; }
public class TestMessage { private static byte[] encode(ProtobufProto.testBuf msg) { return msg.toByteArray(); } private static ProtobufProto.testBuf decode(byte[] body) throws InvalidProtocolBufferException { return ProtobufProto.testBuf.parseFrom(body); } private static ProtobufProto.testBuf createMessage() { ProtobufProto.testBuf.Builder builder = ProtobufProto.testBuf.newBuilder(); builder.setId(1l); builder.setReceive(10001l); builder.setSend(10002l); builder.setContent("this is test"); builder.setType(0); builder.setState(0); builder.setCreateTime(System.currentTimeMillis()); return builder.build(); } public static void main(String[] args) { try { ProtobufProto.testBuf msg1 = createMessage(); System.out.println("11--->"+msg1.toString()); ProtobufProto.testBuf msg2 = decode(encode(msg1)); System.out.println("22--->"+msg1.toString()); System.out.println("33--->"+msg1.equals(msg2)); } catch(Exception e) { e.printStackTrace(); } } }
结合Netty示例
public class ProtobufServer { public void bind(int port) throws Exception { //EventLoopGroup是用来处理IO操作的多线程事件循环器 //bossGroup 用来接收进来的连接 EventLoopGroup bossGroup = new NioEventLoopGroup(); //workerGroup 用来处理已经被接收的连接 EventLoopGroup workerGroup = new NioEventLoopGroup(); try { //启动 NIO 服务的辅助启动类 ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) //配置 Channel .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ProtobufVarint32FrameDecoder()); //处理半包 ch.pipeline().addLast(new ProtobufDecoder(ProtobufProto.testBuf.getDefaultInstance())); ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender()); ch.pipeline().addLast(new ProtobufEncoder()); // 注册handler ch.pipeline().addLast(new ProtobufServerHandler()); } }) .childOption(ChannelOption.SO_KEEPALIVE, true); // 绑定端口,开始接收进来的连接 ChannelFuture f = b.bind(port).sync(); // 等待服务器 socket 关闭 。 f.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port = 8080; new ProtobufServer().bind(port); } }
public class ProtobufServerHandler extends ChannelHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ProtobufProto.testBuf message = (ProtobufProto.testBuf)msg; System.out.println("send---->"+message.toString()); ProtobufProto.testBuf.Builder builder = ProtobufProto.testBuf.newBuilder(); builder.setId(2l); builder.setReceive(10002l); builder.setSend(10001l); builder.setContent("this is server"); builder.setType(0); builder.setState(0); builder.setCreateTime(System.currentTimeMillis()); ctx.writeAndFlush(builder.build()); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 当出现异常就关闭连接 cause.printStackTrace(); ctx.close(); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } }
public class ProtobufClient { public void connect(String host, int port) throws Exception { EventLoopGroup workerGroup = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(workerGroup) .channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(new ProtobufVarint32FrameDecoder()); //处理半包 ch.pipeline().addLast(new ProtobufDecoder(ProtobufProto.testBuf.getDefaultInstance())); ch.pipeline().addLast(new ProtobufVarint32LengthFieldPrepender()); ch.pipeline().addLast(new ProtobufEncoder()); // 注册handler ch.pipeline().addLast(new ProtobufClientHandler()); } }); // Start the client. ChannelFuture f = b.connect(host, port).sync(); // Wait until the connection is closed. f.channel().closeFuture().sync(); } finally { workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { ProtobufClient client = new ProtobufClient(); client.connect("127.0.0.1", 8080); } }
public class ProtobufClientHandler extends ChannelHandlerAdapter{ // 连接成功后,向server发送消息 @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { ProtobufProto.testBuf.Builder builder = ProtobufProto.testBuf.newBuilder(); builder.setId(1l); builder.setReceive(10001l); builder.setSend(10002l); builder.setContent("this is send"); builder.setType(0); builder.setState(0); builder.setCreateTime(System.currentTimeMillis()); ctx.writeAndFlush(builder.build()); } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { ProtobufProto.testBuf message = (ProtobufProto.testBuf)msg; System.out.println("receive---->"+message.toString()); } public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { // 当出现异常就关闭连接 cause.printStackTrace(); ctx.close(); } }
JBoss Marshalling
JBoss Marshalling 是一个Java 对象序列化包,对 JDK 默认的序列化框架进行了优化,但又保持跟 Java.io.Serializable 接口的兼容,同时增加了一些可调的参数和附件的特性, 这些参数和附加的特性, 这些参数和特性可通过工厂类进行配置.
<dependency> <groupId>org.jboss.marshalling</groupId> <artifactId>jboss-marshalling</artifactId> <version>1.4.11.Final</version> </dependency> <dependency> <groupId>org.jboss.marshalling</groupId> <artifactId>jboss-marshalling-serial</artifactId> <version>1.4.11.Final</version> </dependency>
public class MarshallingServer { public void bind(int port) throws Exception { // 配置服务端的NIO线程组 EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .option(ChannelOption.SO_BACKLOG, 128) .handler(new LoggingHandler(LogLevel.INFO)) .childHandler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) { ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder()); ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder()); ch.pipeline().addLast(new MarshallingServerHandler()); } }); // 绑定端口,同步等待成功 ChannelFuture f = b.bind(port).sync(); // 等待服务端监听端口关闭 f.channel().closeFuture().sync(); } finally { // 优雅退出,释放线程池资源 bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { int port = 8080; new MarshallingServer().bind(port); } }
@Sharable public class MarshallingServerHandler extends ChannelHandlerAdapter { @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { Message req = (Message) msg; System.out.println("this send msg --> ["+ req.toString() + "]"); if (2 == req.getId()) { ctx.writeAndFlush(resp(req.getId())); } } private Message resp(long subReqID) { Message resp = new Message(); resp.setId(subReqID); resp.setContent("客户端,我收到你的消息了!"); return resp; } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close();// 发生异常,关闭链路 } }
public final class MarshallingCodeCFactory { /** * 创建Jboss Marshalling解码器MarshallingDecoder * * @return */ public static MarshallingDecoder buildMarshallingDecoder() { final MarshallerFactory marshallerFactory = Marshalling.getProvidedMarshallerFactory("serial"); final MarshallingConfiguration configuration = new MarshallingConfiguration(); configuration.setVersion(5); UnmarshallerProvider provider = new DefaultUnmarshallerProvider(marshallerFactory, configuration); MarshallingDecoder decoder = new MarshallingDecoder(provider, 1024); return decoder; } /** * 创建Jboss Marshalling编码器MarshallingEncoder * * @return */ 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 encoder = new MarshallingEncoder(provider); return encoder; } }
public class MarshallingClient { public void connect(int port, String host) throws Exception { // 配置客户端NIO线程组 EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingDecoder()); ch.pipeline().addLast(MarshallingCodeCFactory.buildMarshallingEncoder()); ch.pipeline().addLast(new MarshallingClientHandler()); } }); // 发起异步连接操作 ChannelFuture f = b.connect(host, port).sync(); // 当代客户端链路关闭 f.channel().closeFuture().sync(); } finally { // 优雅退出,释放NIO线程组 group.shutdownGracefully(); } } /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { int port = 8080; new MarshallingClient().connect(port, "127.0.0.1"); } }
public class MarshallingClientHandler extends ChannelHandlerAdapter { @Override public void channelActive(ChannelHandlerContext ctx) { for (int i = 0; i < 10; i++) { ctx.write(subReq(i)); } ctx.flush(); } private Message subReq(int i) { Message req = new Message(); req.setId(i); req.setContent("服务端,你收到我的消息了吗?"); return req; } @Override public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { System.out.println("this server msg --> [" + msg + "]"); } @Override public void channelReadComplete(ChannelHandlerContext ctx) throws Exception { ctx.flush(); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } }