日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Dubbo自定义异常message过长解决

發布時間:2024/4/14 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Dubbo自定义异常message过长解决 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

title: Dubbo自定義異常message過長解決 tags:

  • dubbo
  • exception
  • message
  • attachment
  • encode categories: dubbo date: 2017-06-25 18:18:53

參考問題Dubbo異常處理

由于dubbo會將自定義異常或者第三方異常包裝直接放入RuntimeException,并且使用了

StringUtils.toString(exception)) 復制代碼

按照dubbo的服務化最佳實踐

異常

  • 建議使用異常匯報錯誤,而不是返回錯誤碼,異常信息能攜帶更多信息,以及語義更友好,
  • 如果擔心性能問題,在必要時,可以通過override掉異常類的fillInStackTrace()方法為空方法,使其不拷貝棧信息,
  • 查詢方法不建議拋出checked異常,否則調用方在查詢時將過多的try...catch,并且不能進行有效處理,
  • 服務提供方不應將DAO或SQL等異常拋給消費方,應在服務實現中對消費方不關心的異常進行包裝,否則可能出現消費方無法反序列化相應異常。

基于現狀目前引用的第三方異常以及自定義異常很難一次性加入到api包中。并且unchecked異常也很難全部聲明到方法簽名上。

遂做了如下改造

/*** Created by qixiaobo on 2017/7/3.*/ @Activate(group = Constants.PROVIDER, before = {"exception"}, value = {"customException"}) public class CustomExceptionFilter implements Filter {private static Logger logger = LoggerFactory.getLogger(CustomExceptionFilter.class);@Overridepublic Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {Result result = invoker.invoke(invocation);if (result.hasException() && GenericService.class != invoker.getInterface()) {try {Throwable exception = result.getException();// 如果是checked異常,直接拋出if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {return result;}// 在方法簽名上有聲明,直接拋出try {Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());Class<?>[] exceptionClassses = method.getExceptionTypes();for (Class<?> exceptionClass : exceptionClassses) {if (exception.getClass().equals(exceptionClass)) {return result;}}} catch (NoSuchMethodException e) {return result;}// 是JDK自帶的異常,直接拋出String className = exception.getClass().getName();if (className.startsWith("java.") || className.startsWith("javax.")) {return result;}// 是Dubbo本身的異常,直接拋出if (exception instanceof RpcException) {return result;}//其他exception ,減少問題,直接將exception序列化成RuntimeException,同時放入指定的異常類型值attachment中// 否則,包裝成RuntimeException拋給客戶端RpcResult rpcResult = new RpcResult(new RuntimeException(exception.getMessage()));rpcResult.setAttachment("customException", exception.getClass().getName());//已經包裝過后續ExceptionFilter無需處理result = rpcResult;} catch (Throwable e) {logger.error(e.getMessage(), e);return result;}}return result;} }customException=com.air.tqb.dubbo.filter.CustomExceptionFilter<dubbo:provider timeout="30000" group="${dubbo.group}" retries="0" owner="qixiaobo" id="f6-provider" filter="customException"/> 復制代碼

效果自然是有的

策略比較簡單:

  • 在ExceptionFilter處理之前提前將異常轉化成RuntimeException,將原異常的message取出,放入RuntimeException
  • 放入Attachment到RpcResult以期許在消費者獲取具體的異常類型。
  • 結果卻是可以拿到較短的message,并且消除了大量的堆棧填充。但是在消費者卻無法獲取指定的attachment。

    直接給出結論DubboCodec中:

    @Override protected void encodeResponseData(Channel channel, ObjectOutput out, Object data) throws IOException {Result result = (Result) data;Throwable th = result.getException();if (th == null) {Object ret = result.getValue();if (ret == null) {out.writeByte(RESPONSE_NULL_VALUE);} else {out.writeByte(RESPONSE_VALUE);out.writeObject(ret);}} else {out.writeByte(RESPONSE_WITH_EXCEPTION);out.writeObject(th);} } 復制代碼

    很明顯在做encodeResponse的時候Dubbo直接取出了對應的類型

  • 如果異常為空取出value
  • 如果value為空則寫入空返回(異步或者oneWay)
  • 如果value不為空則寫入value
  • 否則將異常寫入
  • 很明顯 期間并未操作到attachment。

    那么在請求的時候我們查看一下

    @Override protected void encodeRequestData(Channel channel, ObjectOutput out, Object data) throws IOException {RpcInvocation inv = (RpcInvocation) data;out.writeUTF(inv.getAttachment(Constants.DUBBO_VERSION_KEY, DUBBO_VERSION));out.writeUTF(inv.getAttachment(Constants.PATH_KEY));out.writeUTF(inv.getAttachment(Constants.VERSION_KEY));out.writeUTF(inv.getMethodName());out.writeUTF(ReflectUtils.getDesc(inv.getParameterTypes()));Object[] args = inv.getArguments();if (args != null)for (int i = 0; i < args.length; i++){out.writeObject(encodeInvocationArgument(channel, inv, i));}out.writeObject(inv.getAttachments()); } 復制代碼

    確實從invocation中取出了attachment并寫入請求流中。

    因此在消費者通過DubboCodec是無法將attachment傳給消費者的

    總結

    以上是生活随笔為你收集整理的Dubbo自定义异常message过长解决的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。