QException是项目业务异常基类 按模块划分子类异常,方便定位那块出错
有个来源码属性code作用定位某个功能处理出错逻辑,数字类型节省内存空间,同时减少创建子类的子类
QSocketException 是通信层出错 凡是来自QSocketException 统一认为非法请求,强制关闭socket连接
QJsonException 是json编解码出错 json很流行种数据格式,跨平台特点,经常处理
QEnhanceException 是Javassist动态生成java class技术,用于替换jdk 动态代理
1 public class QException extends RuntimeException { 2 3 private static final long serialVersionUID = -3110633035340065406L; 4 5 private short code; 6 7 public short getCode() { 8 return code; 9 } 10 11 public QException(short code, String message, Throwable cause) { 12 super(message, cause); 13 this.code = code; 14 } 15 16 public QException(short code) { 17 super(); 18 this.code = code; 19 } 20 21 public QException(short code, String message) { 22 super(message); 23 this.code = code; 24 } 25 26 }
接下来应用异常
首先要找到所有业务调用的主入口,由于用的是netty通信框架,对于服务端来讲要找到接收数据的方法
ChannelDuplexHandler 是netty提供的业务实现的类,其中channelRead是接收数据的方法
1 @Sharable 2 public class QMessageHandler extends ChannelDuplexHandler { 3 4 private QDispenseHandler dispenseHandler; 5 6 public QMessageHandler(QDispenseHandler dispenseHandler) { 7 this.dispenseHandler = dispenseHandler; 8 } 9 10 @Override 11 public void channelActive(ChannelHandlerContext ctx) throws Exception { 12 dispenseHandler.doConnect(ctx); 13 super.channelActive(ctx); 14 } 15 16 @Override 17 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception { 18 dispenseHandler.doReceive(msg, ctx); 19 super.channelRead(ctx, msg); 20 } 21 22 @Override 23 public void channelInactive(ChannelHandlerContext ctx) throws Exception { 24 dispenseHandler.doClose(ctx); 25 super.channelInactive(ctx); 26 } 27 }
QDispenseHandler.class
当业务处理失败时,响应三种策略
1.优先处理来自QSocketException强制关闭socket连接
2.业务边界QException
3.未知错误Exception
第一种情况不用返回响应码
第二三种情况是否返回根据客户端请求状态决定 boolean response = packet.hasStatus(QPacket.MASK_RESPONSE)
1 public void doReceive(Object msg, ChannelHandlerContext ctx) { 2 if (msg instanceof QPacket) { 3 pool.execute(() -> { 4 doReceive0((QPacket) msg, ctx); 5 }); 6 } 7 } 8 9 private void doReceive0(QPacket packet, ChannelHandlerContext ctx) { 10 11 boolean response = packet.hasStatus(QPacket.MASK_RESPONSE); 12 try { 13 //doReceive ... 处理省略细节 14 15 } catch (QSocketException e) { 16 // socket异常 关闭连接 17 packet.responseCode(e.getCode()); 18 LOGGER.error("QSocketException msg {} error : {}", QCodeUtil.getDes( e.getCode()), e); 19 if (response) { 20 ChannelFuture future = ctx.channel().writeAndFlush(packet); 21 future.addListener(new GenericFutureListener<Future<? super Void>>() { 22 @Override 23 public void operationComplete(Future<? super Void> future) throws Exception { 24 NettyUtil.closeChannel(CLOSE_SOURCE.SOCKET_ERROR, false, ctx.channel()); 25 } 26 }); 27 } else { 28 NettyUtil.closeChannel(CLOSE_SOURCE.SOCKET_ERROR, false, ctx.channel()); 29 } 30 return; 31 } catch (QException e) { 32 // 业务异常 响应失败 33 packet.responseCode(e.getCode()); 34 LOGGER.error("QException msg {} error : {}",QCodeUtil.getDes( e.getCode()), e); 35 } catch (Exception e) { 36 // 未知异常 响应失败 37 packet.responseCode(QCode.ERROR_UNKNOWN); 38 LOGGER.error("UNKNOWNException error : {}", e); 39 } 40 if (response) { 41 ctx.channel().writeAndFlush(packet); 42 } 43 }