dubbo 自身提供了filter 的擴(kuò)展,用于入?yún)⒑又剩鰠⒓讲眩?guī)范返回參數(shù) 都是非常實(shí)用的,本文就以重寫(xiě)dubbo 自身的ExceptionFilter 為例 詳細(xì)說(shuō)明 dubbo 的filter功能
我們的項(xiàng)目中很多情況下都會(huì)拋出一些自定義異常來(lái)替代返回錯(cuò)誤碼掀鹅,但是在dubbo服務(wù)中往往不能達(dá)到理想的效果散休,因?yàn)閐ubbo 的ExceptionFilter過(guò)濾器會(huì)將我們的異常信息進(jìn)行包裝,我們重寫(xiě)一下ExceptioFilter 就可以輕松的實(shí)現(xiàn)我們的效果
- 將ExceptionFilter copy 到我們的項(xiàng)目改名為DubboExceptionFilter或者新建一個(gè)Filter 繼承com.alibaba.dubbo.rpc.Filter
import com.alibaba.dubbo.common.Constants;
import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.common.logger.Logger;
import com.alibaba.dubbo.common.logger.LoggerFactory;
import com.alibaba.dubbo.common.utils.ReflectUtils;
import com.alibaba.dubbo.common.utils.StringUtils;
import com.alibaba.dubbo.rpc.Filter;
import com.alibaba.dubbo.rpc.Invocation;
import com.alibaba.dubbo.rpc.Invoker;
import com.alibaba.dubbo.rpc.Result;
import com.alibaba.dubbo.rpc.RpcContext;
import com.alibaba.dubbo.rpc.RpcException;
import com.alibaba.dubbo.rpc.RpcResult;
import com.alibaba.dubbo.rpc.service.GenericService;
import java.lang.reflect.Method;
@Activate(group = Constants.PROVIDER)
public class DubboExceptionFilter implements Filter {
private final Logger logger;
public DubboExceptionFilter() {
this(LoggerFactory.getLogger(DubboExceptionFilter.class));
}
public DubboExceptionFilter(Logger logger) {
this.logger = logger;
}
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
try {
Result result = invoker.invoke(invocation);
if (result.hasException() && GenericService.class != invoker.getInterface()) {
try {
Throwable exception = result.getException();
// directly throw if it's checked exception
if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) {
return result;
}
// directly throw if the exception appears in the signature
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;
}
// for the exception not found in method's signature, print ERROR message in server's log.
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().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 result;
}
// directly throw if it's JDK exception
String className = exception.getClass().getName();
if (className.startsWith("java.") || className.startsWith("javax.")) {
return result;
}
if (className.startsWith("com.dliberty")) {
return result;
}
// directly throw if it's dubbo exception
if (exception instanceof RpcException) {
return result;
}
// otherwise, wrap with RuntimeException and throw back to the client
return new RpcResult(new RuntimeException(StringUtils.toString(exception)));
} catch (Throwable e) {
logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost()
+ ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
+ ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
return result;
}
}
return result;
} catch (RuntimeException e) {
logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost()
+ ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName()
+ ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e);
throw e;
}
}
}
image.png
在此處加上一段代碼來(lái)過(guò)濾我們項(xiàng)目中的異常以免被dubbo 重新封裝為 RpcException
-
在resources目錄下添加純文本文件META-INF/dubbo/com.alibaba.dubbo.rpc.Filter并添加內(nèi)容
dubboExceptionFilter=com.dliberty.core.exception.DubboExceptionFilter
image.png
-
修改dubbo 的配置文件乐尊,將DubboExceptionFilter加載進(jìn)去并且去掉自身的ExceptionFilter
<dubbo:provider filter="dubboExceptionFilter,-exception" ></dubbo:provider>