@@ -0,0 +1,105 @@
package cn.iocoder.common.framework.dubbo ;
import cn.iocoder.common.framework.exception.ServiceException ;
import org.apache.dubbo.common.Constants ;
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.* ;
import org.apache.dubbo.rpc.filter.ExceptionFilter ;
import org.apache.dubbo.rpc.service.GenericService ;
import java.lang.reflect.Method ;
/**
* 基于 {@link org.apache.dubbo.rpc.filter.ExceptionFilter} 实现
*
* 主要目的是, 一些全局性的异常, 能够返回。因为, Dubbo Consumer 能够保证,一定会引入全局性的异常。
*/
@Activate ( group = Constants . PROVIDER )
public class DubboExceptionFilter implements Filter {
private final Logger logger ;
public DubboExceptionFilter ( ) {
this ( LoggerFactory . getLogger ( ExceptionFilter . class ) ) ;
}
public DubboExceptionFilter ( Logger logger ) {
this . logger = logger ;
}
@Override
public Result invoke ( Invoker < ? > invoker , Invocation invocation ) throws RpcException {
try {
return invoker . invoke ( invocation ) ;
} 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 ;
}
}
@Override
public Result onResponse ( Result result , Invoker < ? > invoker , Invocation 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 ;
} else if ( exception instanceof ServiceException ) { // add by 芋艿。如果是业务异常,继续抛出
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 ;
}
// 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 ;
}
}