对象序列化, 目的是为了实现对象的网络传输和本地持久化
如果使用java的序列化, 码流较大. 因此多用FastjsonSerialize, KryoSerialize,FSTSerialize等
在本例中使用FSTSerialize进行编解码传输javabean。
一,导入依赖jar
<dependencies>
<!-- Netty依赖包
https://mvnrepository.com/artifact/io.netty/netty-all -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.25.Final</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.22</version>
</dependency>
<!--fst序列化-->
<dependency>
<groupId>de.ruedigermoeller</groupId>
<artifactId>fst</artifactId>
<version>2.52</version>
</dependency>
<!--监控本机cpu,内存等信息-->
<dependency>
<groupId>org.fusesource</groupId>
<artifactId>sigar</artifactId>
<version>1.6.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
</plugins>
</build>
二,服务端编码
public class Server {
private final int port;
public Server(int port) {
this.port = port;
}
public static void main(String[] args) throws Exception {
int port = 8081;
new Server(port).start();
}
public void start() throws Exception {
NioEventLoopGroup bossGroup = new NioEventLoopGroup(1);
NioEventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch) {
ch.pipeline()
// 添加编解码. 发送自定义的类型, 而Handler的方法接收的msg参数的实际类型也是相应的自定义类了
.addLast(new TinyDecoder(Request.class))
.addLast(new TinyEncoder(Response.class))
.addLast(new ServerHandler());
}
})
.option(ChannelOption.SO_BACKLOG, 128)
.childOption(ChannelOption.SO_KEEPALIVE, true);
ChannelFuture f = b.bind(port).sync();
System.out.println(Server.class.getName() + " 服务器端开启并监听端口号: " + f.channel().localAddress());
f.channel().closeFuture().sync();
} finally {
//释放 channel 和 块,直到它被关闭
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}
public class ServerHandler extends SimpleChannelInboundHandler<Request> {
@Override
protected void channelRead0(ChannelHandlerContext ctx, Request request) throws Exception {
System.out.println("服务端接收到的消息 : " + request.getRequestId());
System.out.println("服务端接收到的消息 : " + request.getParameters().toString());
System.out.println("服务端接收到的消息 : " + request.getClass());
Response response = new Response();
response.setRequestId(2L);
response.setError("success");
User user = new User();
user.setUsername("测试");
user.setPassword("1234");
user.setAge(21);
response.setResult(user);
//addListener是非阻塞的,异步执行。它会把特定的ChannelFutureListener添加到ChannelFuture中,然后I/O线程会在I/O操作相关的future完成的时候通知监听器。
ctx.writeAndFlush(response).addListener((ChannelFutureListener) channelFuture ->
System.out.println("接口响应:" + request.getRequestId())
);
}
}
三,客户端编码
public class Client {
private final String host;
private final int port;
public Client(String host, int port) {
this.host = host;
this.port = port;
}
public static void main(String[] args) throws Exception {
final String host = "127.0.0.1";
final int port = 8081;
new Client(host, port).start();
}
public void start() throws Exception {
EventLoopGroup group = new NioEventLoopGroup();
try {
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.remoteAddress(new InetSocketAddress(host, port))
.handler(new ChannelInitializer<SocketChannel>() {
@Override
public void initChannel(SocketChannel ch)
throws Exception {
ch.pipeline()
// 添加编解码. 发送自定义的类型, 而Handler的方法接收的msg参数的实际类型也是相应的自定义类了
.addLast(new TinyEncoder(Request.class))
.addLast(new TinyDecoder(Response.class))
.addLast(new ClientHandler());
}
});
ChannelFuture f = b.connect().sync();
f.channel().closeFuture().sync();
} finally {
group.shutdownGracefully().sync();
}
}
}
public class ClientHandler extends SimpleChannelInboundHandler<Response> {
/**
* 通道注册
*
* @param ctx
* @throws Exception
*/
@Override
public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
super.channelRegistered(ctx);
}
/**
* 服务器的连接被建立后调用
* 建立连接后该 channelActive() 方法被调用一次
*
* @param ctx
*/
@Override
public void channelActive(ChannelHandlerContext ctx) {
Request request = new Request();
request.setRequestId(3L);
User user = new User();
user.setUsername("测试客户端");
user.setPassword("4567");
user.setAge(21);
request.setParameters(user);
//当被通知该 channel 是活动的时候就发送信息
ctx.writeAndFlush(request);
}
@Override
protected void channelRead0(ChannelHandlerContext ctx, Response response) throws Exception {
System.out.println("服务器发来消息 : " + response.getRequestId());
System.out.println("服务器发来消息 : " + response.getError());
System.out.println("服务器发来消息 : " + response.getResult().toString());
}
/**
* 捕获异常时调用
*
* @param ctx
* @param cause
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx,
Throwable cause) {
//记录错误日志并关闭 channel
cause.printStackTrace();
ctx.close();
}
}
四,通用封装类
public class FstSerializer {
private static FSTConfiguration conf = FSTConfiguration.createDefaultConfiguration();
/**
* 反序列化
*
* @param data
* @param clazz
* @param <T>
* @return
*/
public static <T> T deserialize(byte[] data, Class<T> clazz) {
return (T) conf.asObject(data);
}
/**
* 序列化
*
* @param obj
* @param <T>
* @return
*/
public static <T> byte[] serialize(T obj) {
return conf.asByteArray(obj);
}
}
public class TinyDecoder extends ByteToMessageDecoder {
private Class<?> genericClass;
public TinyDecoder(Class<?> genericClass) {
this.genericClass = genericClass;
}
/**
* 解码
*
* @param ctx
* @param in
* @param out
*/
@Override
public final void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
int size = in.readableBytes();
byte[] data = new byte[size];
in.readBytes(data);
Object obj = FstSerializer.deserialize(data, genericClass);
out.add(obj);
}
}
@ChannelHandler.Sharable
public class TinyEncoder extends MessageToByteEncoder {
private Class<?> genericClass;
public TinyEncoder(Class<?> genericClass) {
this.genericClass = genericClass;
}
/**
* 编码
* @param ctx
* @param in
* @param out
* @throws Exception
*/
@Override
public void encode(ChannelHandlerContext ctx, Object in, ByteBuf out) {
if (genericClass.isInstance(in)) {
byte[] data = FstSerializer.serialize(in);
out.writeBytes(data);
}
}
}
public class Request implements Serializable {
private static final long serialVersionUID = -2747321595912488569L;
private Long requestId;
private Object parameters;
//get set tostring方法
}
public class Response implements Serializable {
private static final long serialVersionUID = -3136380221020337915L;
private Long requestId;
private String error;
private Object result;
//get set toString
}