目录
需求描述
springboot项目要对接第三方接口,第三方采用netty作为服务端,要求先登录,然后15s内发心跳保持连接,然后就可以正常调用接口拿数据、入库、返回前端。
两个问题
springboot服务需要写netty客户端去登录与心跳保持。因为首次用netty不太熟,调试期间发现两个问题记录下
1、心跳报错。
2、springboot项目启动后netty正常,但是无法响应前端请求。
以上两个问题归根结底是对netty不熟造成的
问题一-心跳报错
代码
private final ByteBuf heartbeatMessage;
public NettyClientMessageHandlerAdapter() {
HeartBeatMsg heartBeatMsg=new HeartBeatMsg();
String heatMsg=JSON.toJSONString(heartBeatMsg).concat("**");
byte[] heartbeat=heatMsg.getBytes();
heartbeatMessage = Unpooled.buffer(heartbeat.length);
heartbeatMessage.writeBytes(heartbeat);
}
代码本意是心跳是信息是固定的,索性就定义一个ByteBuf 用于存储,以后发送心跳直接发送这个bytebuf就行了。
原因
实际报错信息如下:
io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1
详解见https://blog.csdn.net/qq_32447321/article/details/82912925
其实计数器减一的操作是在flush时候操作的,这也符合逻辑。
解决
1、在每次法心跳的时候重新组装心跳信息
2、把heartbeatMsg引用计数+1。ReferenceCountUtil.retain(heartbeatMsg);
问题二-web服务不可用
代码
future.channel().closeFuture().sync();
netty作为客户端连接服务端后,直接阻塞,发送心跳
原因
造成不可用的原因就是同步阻塞,springboot服务和netty是在同一个线程去启动的,当先执行到netty的上述代码时会阻塞住主线程,导致springboot内置tomcat无法正常启动
解决
1、启动netty客户端在子线程中启动
new Thread(new Runnable() {
@Override
public void run() {
try {
这里启动netty客户端
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
2、springboot启动完成后再去启动netty客户端,可以用ApplicationRunner去实现
public class NettyRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
启动netty客户端
}
}