开发者社区 > 云原生 > 正文

dubbo-java 3.2 beta 服务端全局异常处理filter 无法按预期执行

目的:

在provider端 使用filter 拦截provider 处理过程的异常; 在业务代码中抛出异常后,没有按预期执行 filter 中onResponse 方法,而是执行了onError 方法,在onError 方法中,又无法对结果或异常信息进行包装改写;

问题项目示例地址:https://github.com/gebizhuxiaowang/dubbo-demo 使用postMan调用gRPC 接口:helloException 可复现;

求助:

在服务端拦截全局异常的方法是否正确? 若正确,上述例子中为什么无法预期执行对应的方法? filter 代码如下:

package com.example.dubbo.filter;

import org.apache.dubbo.common.constants.CommonConstants; import org.apache.dubbo.common.extension.Activate; import org.apache.dubbo.common.logger.Logger; import org.apache.dubbo.common.logger.LoggerFactory; import org.apache.dubbo.common.utils.ReflectUtils; import org.apache.dubbo.common.utils.StringUtils; import org.apache.dubbo.rpc.Filter; import org.apache.dubbo.rpc.Invocation; import org.apache.dubbo.rpc.Invoker; import org.apache.dubbo.rpc.Result; import org.apache.dubbo.rpc.RpcContext; import org.apache.dubbo.rpc.RpcException; import org.apache.dubbo.rpc.service.GenericService;

import java.lang.reflect.Method;

/** * @version 1.0 * @classname DubboProviderExceptionFilter * @description todo */ @Activate(group = CommonConstants.PROVIDER) public class DubboProviderExceptionFilter implements Filter, Filter.Listener {

private static Logger log = LoggerFactory.getLogger(DubboProviderExceptionFilter.class);

@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
    // return invoker.invoke(invocation);
    Result appResponse = invoker.invoke(invocation);
    if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
        try {
            Throwable e = appResponse.getException();
            log.error(" [MAGICAL-DUBBO] Fail to MagicalDubboRpcExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
        } catch (Throwable e) {
            log.error(" [MAGICAL-DUBBO] Fail to MagicalDubboRpcExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
            // return AsyncRpcResult.newDefaultAsyncResult(R.fail(65510, "远程服务调用发生异常"), invocation);
        }
    }
    return appResponse;
}

// 业务代码抛异常后,不会进入这个方法
@Override
public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) {
    if (appResponse.hasException() && GenericService.class != invoker.getInterface()) {
        try {
            Throwable exception = appResponse.getException();

            // directly throw if it's checked exception
            if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
                return;
            }
            // directly throw if the exception appears in the signature
            try {
                Method method = invoker.getInterface().getMethod(invocation.getMethodName(),
                        invocation.getParameterTypes());
                Class<?>[] exceptionClasses = method.getExceptionTypes();
                for (Class<?> exceptionClass : exceptionClasses) {
                    if (exception.getClass().equals(exceptionClass)) {
                        return;
                    }
                }
            } catch (NoSuchMethodException e) {
                return;
            }


            // for the exception not found in method's signature, print ERROR message in server's log.
            log.error("Got unchecked and undeclared exception which called by " + RpcContext.getServiceContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + exception.getClass().getName() + ": " + exception.getMessage(), exception);

            // directly throw if exception class and interface class are in the same jar file.
            String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
            String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
            if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) {
                return;
            }
            // directly throw if it's JDK exception
            String className = exception.getClass().getName();
            if (className.startsWith("java.") || className.startsWith("javax.")) {
                return;
            }

            // directly throw if it's dubbo exception
            if (exception instanceof RpcException) {
                return;
            }

            // otherwise, wrap with RuntimeException and throw back to the client
            appResponse.setException(new RuntimeException(StringUtils.toString(exception)));
        } catch (Throwable e) {
            log.warn("Fail to ExceptionFilter when called by " + RpcContext.getServiceContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
        }
    }
}

@Override
public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) {
    log.error("Got unchecked and undeclared exception which called by " + RpcContext.getServiceContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + t.getClass().getName() + ": " + t.getMessage(), t);

}

}

业务处理类抛出的异常是自定义异常;

原提问者GitHub用户gebizhuxiaowang

展开
收起
大圣东游 2023-05-11 15:42:27 155 0
1 条回答
写回答
取消 提交回答
  • 我这里是可以的,你可以使用https://github.com/apache/dubbo-samples/blob/master/3-extensions/protocol/dubbo-samples-triple/src/test/java/org/apache/dubbo/sample/tri/BaseTriPojoClientTest.java 中的org.apache.dubbo.sample.tri.BaseTriPojoClientTest#greetException 试试

    回答2.png

    原回答者GitHub用户EarthChen

    2023-05-12 10:16:38
    赞同 展开评论 打赏

阿里云拥有国内全面的云原生产品技术以及大规模的云原生应用实践,通过全面容器化、核心技术互联网化、应用 Serverless 化三大范式,助力制造业企业高效上云,实现系统稳定、应用敏捷智能。拥抱云原生,让创新无处不在。

相关电子书

更多
Dubbo开源现状与2.7规划 立即下载
Dubbo分布式服务治理实战 立即下载
《Dubbo 3.0 前瞻》 立即下载