目前以上功能基本实现,接下来看看功能使用介绍
我们以服务端来举例,可打包到本地仓库引入使用
需要配置启动参数,协议那里如果不自定义则必填否则服务端不会启动(怎么自定义后面说),下面我们介绍内置的三种协议的配置启动
http-config为http参数配置项,不配也可以有默认值
配置如下:
数据处理类自己编写,如同netty一样,只需要打上 @NettyServerHandler 注解即可,如:
@NettyServerHandler
public class HttpBaseHandler extends SimpleChannelInboundHandler {
private final static Logger log= LoggerFactory.getLogger(HttpBaseHandler.class);
@Resource
private ApplicationEventPublisher applicationContext;
public HttpBaseHandler(ApplicationEventPublisher applicationContext){
this.applicationContext=applicationContext;
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpRequest t) throws Exception {
log.info("http请求 uri:{},method:{}",t.uri(),t.method());
DefaultFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.content().writeBytes(JSON.toJSONBytes("Hello"));
response.headers().add(HttpHeaderNames.CONTENT_TYPE, HttpHeaderValues.APPLICATION_JSON+";charset=UTF-8");
response.headers().add(HttpHeaderNames.CONTENT_LENGTH,response.content().readableBytes());
channelHandlerContext.writeAndFlush(response);
}
}
启动springboot项目测试:
打开浏览器,访问127.0.0.1:8888,就可以看到请求结果了
由于WebSocket也同样会采用Http编解码,所以http的配置也同时会满足WebSocket,一样都有默认值,可以不配置
配置如下:
数据处理类自己编写,如同netty一样,只需要打上 @NettyServerHandler 注解即可,如:
@NettyServerHandler
public class WebSocketHandler extends SimpleChannelInboundHandler {
private final static Logger log= LoggerFactory.getLogger(WebSocketHandler.class);
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
super.channelActive(ctx);
log.info("建立连接");
}
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
log.info("收到消息:"+textWebSocketFrame.text());
channelHandlerContext.writeAndFlush(new TextWebSocketFrame(textWebSocketFrame.text()));
}
}
我们准备一个WebSocket的客户端 html :
Netty WebSocket测试
启动springboot项目测试:
普通的长连接也是需要自定义协议的,这里我内嵌了一个自己的协议,也就是博客里面写的那一套
配置如下:
数据处理类自己编写,如同netty一样,只需要打上 @NettyServerHandler 注解即可,如:
@NettyServerHandler
public class MyConfigHandler extends ChannelInboundHandlerAdapter {
private static final Logger log = LoggerFactory.getLogger(MyConfigHandler.class);
// 读取信息调用
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
// 和NIO一样有缓冲区 ByteBuf就是对ByteBuffer做了一层封装
NettyBody msg1 = (NettyBody) msg;
// 读取数据
log.info("客户端信息:" + JSON.toJSON(msg1));
}
// 连接事件 连接成功调用
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
SocketAddress socketAddress = ctx.channel().remoteAddress();
log.info(socketAddress + " 已连接");
// 发送数据
ctx.writeAndFlush(new NettyMsg(ServiceCodeEnum.TEST_TYPE,"Hello Client!"));
}
// 断开连接调用
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
log.info(ctx.channel().remoteAddress() + " 已断开连接");
}
// 读取信息完成事件 信息读取完成后调用
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
}
// 异常处理 发生异常调用
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
log.error("全局异常信息 ex={}", cause.getMessage(), cause);
ctx.close();
}
}
启动springboot项目测试:
内置的协议就以上三种,最后一个就是默认的自定义,这个只会加入被注解标识的Handler,无任何内置的编解码或者Handler
http协议是不需要心跳的,webSocket和socket两种都已经内嵌了心跳的处理了,我们只需要配置一下,然后监听心跳事件就可以了
此配置代表5s触发一次读事件的空闲检测
这里将Netty的空间检测事件转化为了spring中的事件机制,所以我们需要监听NettyServerIdleEvent事件,并将这个Listener注入到spring容器中,如下:
@Component
public class NettyServerHeartTestListener {
private static final Logger log = LoggerFactory.getLogger(NettyServerHeartTestListener.class);
public NettyServerHeartTestListener() {
}
@EventListener({NettyServerIdleEvent.class})
public void serverIdleHandler(NettyServerIdleEvent event) {
NettyServerNettyIdleEntity source = (NettyServerNettyIdleEntity) event.getSource();
// 获取心跳配置
NettyServerHeartConfig serverHeartConfig = source.getServerHeartConfig();
// 获取netty管道 上下文
ChannelHandlerContext ctx = source.getCtx();
// 获取触发的事件
IdleState state = source.getEvt().state();
log.info("心跳事件触发:" + source.getEvt().state());
}
}
可以看到在没消息接收的时候,每5s就会触发一次
我们知道Netty中数据处理类都是被放入管道中的,可以多个,类似责任链模式,所以我们自己的数据处理类怎么编排呢?主要靠 @NettyServerHandler 注解,里面有个order字段设置排序,被该注解标记的Handler最终都会被收集,并根据Order字段来排序,依次加入到Netty的管道中,order越小,越先加入
我们看一下一个常规的Netty服务端启动,大致可分为三个部分:
关于第一个部分现在只做了简单的配置:端口、线程数,option的配置还没做
关于第二个部分,数据处理器,我们是可以直接将这块替换的
继承NettyServerHandlerInitializer类,并注入到容器中即可替换,如下:
@Component
public class TestInit extends NettyServerHandlerInitializer {
// nettyServerConfig 服务端的配置类
// context Spring容器上下文
// nettyServerChannelInit 内置的一些协议初始化方法
public TestInit(NettyServerConfig nettyServerConfig, ApplicationContext context, NettyServerChannelInit nettyServerChannelInit) {
super(nettyServerConfig, context, nettyServerChannelInit);
}
@Override
protected void initChannel(Channel channel) throws Exception {
// super.initChannel(channel);
// 这里就可以做自己的处理
}
}
关于第三个部分,管道处理类的设置,现在是有内置的一些协议,当然也是支持完成自定义的
实现NettyServerChannelInit接口,并注入到容器中就可以了,如下:
NettyServerChannelInit接口有两个方法:
@Component
public class TestInit implements NettyServerChannelInit {
@Override
public void initChannelHandlers(Channel channel, NettyServerConfig nettyServerConfig, ApplicationContext context) {
}
}
可以看到关于数据处理方面,有三个方向可以拓展自定义的:
客户端的使用配置基本是复刻的服务端,就是在协议方面,没有Http和Websocket了,只有内置的一个自定义协议,同样的只需要配置就能直接启动
与服务端不同的点:
由于是客户端断线重连是必不可少的,所以内置了断线重连机制(也就是博客中说的那种)
配置如下(有默认值不配也行):
看看效果:
启动连接失败,重连:
中途断线重连:
目前这只是个初版,为了增加Netty移植性以及简化Netty在Springboot项目中的操作,肯定有很多欠缺的地方(说不定还有bug),望大佬们多多建议,后续可能会加入以下功能:
链接: 源码地址
大佬有问题轻点喷!多建议