dubbo-源码阅读之Filter默认实现
SPI配置的默认实现
cache=com.alibaba.dubbo.cache.filter.CacheFilter validation=com.alibaba.dubbo.validation.filter.ValidationFilter echo=com.alibaba.dubbo.rpc.filter.EchoFilter generic=com.alibaba.dubbo.rpc.filter.GenericFilter genericimpl=com.alibaba.dubbo.rpc.filter.GenericImplFilter token=com.alibaba.dubbo.rpc.filter.TokenFilter accesslog=com.alibaba.dubbo.rpc.filter.AccessLogFilter activelimit=com.alibaba.dubbo.rpc.filter.ActiveLimitFilter classloader=com.alibaba.dubbo.rpc.filter.ClassLoaderFilter context=com.alibaba.dubbo.rpc.filter.ContextFilter consumercontext=com.alibaba.dubbo.rpc.filter.ConsumerContextFilter exception=com.alibaba.dubbo.rpc.filter.ExceptionFilter executelimit=com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter deprecated=com.alibaba.dubbo.rpc.filter.DeprecatedFilter compatible=com.alibaba.dubbo.rpc.filter.CompatibleFilter timeout=com.alibaba.dubbo.rpc.filter.TimeoutFilter trace=com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter future=com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter monitor=com.alibaba.dubbo.monitor.support.MonitorFilter

Consumer
ConsumerContextFilter
记录一些基础信息到当前线程的PRCContext
@Activate(
group = {"consumer"},
order = -10000
)
public class ConsumerContextFilter implements Filter {
public ConsumerContextFilter() {
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
/***
* 从线程缓存获取本次RpcContext.getContext()
* 设置一些本次请求的基础信息到RpcContext
*/
RpcContext.getContext().setInvoker(invoker)
.setInvocation(invocation)
.setLocalAddress(NetUtils.getLocalHost(), 0)
.setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
if (invocation instanceof RpcInvocation) {
((RpcInvocation)invocation).setInvoker(invoker);
}
Result var3;
try {
/**
* 客户端相关参数是根据 invocation传递给消费者的 可以打断点看 也可以自定义一些数据 比如traceId
*/
var3 = invoker.invoke(invocation);
} finally {
RpcContext.getContext().clearAttachments();
}
return var3;
}
}
ActiveLimitFilter
例子
同时只支持1的并发量
<dubbo:method actives="1" ... />
源码
ActiveLimitFilter主要用于 限制同一个客户端对于一个服务端方法的并发调用量(客户端限流)。
/**
* 控制调用服务的并发量 限流
* 同时支持多少请求
*/
@Activate(
group = {"consumer"},
value = {"actives"}
)
public class ActiveLimitFilter implements Filter {
public ActiveLimitFilter() {
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
URL url = invoker.getUrl();
String methodName = invocation.getMethodName();
//获得 <dubbo:reference actives="1"> actives的数量
int max = invoker.getUrl().getMethodParameter(methodName, "actives", 0);
//获取当前service当前方法的请求数量
RpcStatus count = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName());
long timeout;
//配置并发控制大于0才写
if (max > 0) {
//获得当前方法的等待时间
timeout = (long)invoker.getUrl().getMethodParameter(invocation.getMethodName(), "timeout", 0);
long start = System.currentTimeMillis();
long remain = timeout;
//判断是否大于并发数 如果大于则等待
int active = count.getActive();
if (active >= max) {
synchronized(count) {
/**
*1.while循环是有必要的
* 当收到其他线程notify 获得执行权
* 但是这个时候其他线程提前进入(active >= max) 判断为false获得执行权 count+1
* 这个时候 还需要while判断是否还有空闲请求 否则继续wait
*
*/
while((active = count.getActive()) >= max) {
try {
//超时时间为 配置的超时时间
count.wait(remain);
} catch (InterruptedException var32) {
;
}
long elapsed = System.currentTimeMillis() - start;
remain = timeout - elapsed;
//当其他线程通知等待线程执行 判断是否超时 如果超时了则不执行了
if (remain <= 0L) {
throw new RpcException("Waiting concurrent invoke timeout in client-side for service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", elapsed: " + elapsed + ", timeout: " + timeout + ". concurrent invokes: " + active + ". max concurrent invoke limit: " + max);
}
}
}
}
}
boolean var28 = false;
Result var10;
try {
var28 = true;
timeout = System.currentTimeMillis();
//获得执行权的 count+1
RpcStatus.beginCount(url, methodName);
try {
//执行
Result result = invoker.invoke(invocation);
//执行完毕关闭
RpcStatus.endCount(url, methodName, System.currentTimeMillis() - timeout, true);
var10 = result;
var28 = false;
} catch (RuntimeException var31) {
RpcStatus.endCount(url, methodName, System.currentTimeMillis() - timeout, false);
throw var31;
}
} finally {
if (var28) {
if (max > 0) {
//通知等待的线程执行
synchronized(count) {
count.notify();
}
}
}
}
if (max > 0) {
synchronized(count) {
//通知等待的线程执行
count.notify();
}
}
return var10;
}
}
FutureFilter
用于处理事件 异步回调 同步回调 异常回调
例子
1.自定义一个event接口
/**
* @author liqiang
* @date 2019/11/28 10:34
* @Description:定义一个抽象接口实现
*/
public interface IEvent {
/**
* 从源码可以看到 传递的这2个参数
*
* @param throwable
* @param args
*/
public void onThrow(Throwable throwable, Object[] args);
/**
* 从源码可以看到传递这2个参数
* async为true表示异步回调
* async为false 表示调用完成回调
*
* @param params
*/
public void onReturn(Object[] params);
/**
* 参数列表要跟执行列表一样
* 这里参数列表不固定 应该抽出去 因为是demo 就写一起
*/
public void onInvoke(PrizeDrawReqDto prizeDrawReqDto);
}
2.实现类
/**
* @author liqiang
* @date 2019/11/28 10:46
* @Description: 回调实现类
*/
public class PagePromotionServicePrizeDrawEvent implements IEvent {
/**
* 从源码可以看到 传递的这2个参数
* 发生异常时回调
* @param throwable
* @param args
*/
@Override
public void onThrow(Throwable throwable, Object[] args) {
System.out.println(String.format("异常回调,参数:%s",args.toString()));
}
/**
* 从源码可以看到传递这2个参数
* async为true表示异步回调
* async为false 表示调用完成回调
*
* @param params
*/
@Override
public void onReturn(Object[] params) {
System.out.println(String.format("onReturn回调:",params.toString()));
}
/**
* 参数列表要跟执行列表一样
*执行前回调
* @param prizeDrawReqDto
*/
@Override
public void onInvoke(PrizeDrawReqDto prizeDrawReqDto) {
System.out.println(String.format("onInvoke执行前回调:",prizeDrawReqDto.toString()));
}
}
2.consumer配置
<!--定义回调实现类的bean-->
<bean id="pagePromotionServicePrizeDrawEvent" class="com.bozhi.notify.PagePromotionServicePrizeDrawEvent"></bean>
<dubbo:reference id="frontendPagePromotionService"
url="dubbo://127.0.0.1:23888/com.biz.soa.service.pagepromotion.frontend.PagePromotionService"
interface="com.biz.soa.service.pagepromotion.frontend.PagePromotionService" check="false">
<dubbo:method async="true" name="prizeDraw"
onreturn="pagePromotionServicePrizeDrawEvent.onReturn"
oninvoke="pagePromotionServicePrizeDrawEvent.onInvoke"
onthrow="pagePromotionServicePrizeDrawEvent.onThrow"></dubbo:method>
</dubbo:reference>
源码
@Activate(
group = {"consumer"}//消费端的过滤器
)
public class FutureFilter implements Filter {
protected static final Logger logger = LoggerFactory.getLogger(com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.class);
public FutureFilter() {
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//在url后面获取是否是异步
boolean isAsync = RpcUtils.isAsync(invoker.getUrl(), invocation);
//执行调用前时间 onInvoker
this.fireInvokeCallback(invoker, invocation);
//执行invoke
Result result = invoker.invoke(invocation);
//判断是同步还是异步
if (isAsync) {
//处理异步调用回调
this.asyncCallback(invoker, invocation);
} else {
//处理同步调用回调
this.syncCallback(invoker, invocation, result);
}
return result;
}
private void syncCallback(Invoker<?> invoker, Invocation invocation, Result result) {
//是否发生异常 如果发生调用
if (result.hasException()) {
//调用异常回调
this.fireThrowCallback(invoker, invocation, result.getException());
} else {
//触发onReturn
this.fireReturnCallback(invoker, invocation, result.getValue());
}
}
private void asyncCallback(final Invoker<?> invoker, final Invocation invocation) {
//获取异步调用的Future
Future<?> f = RpcContext.getContext().getFuture();
//判断是否是FutureAdapter适配器
if (f instanceof FutureAdapter) {
ResponseFuture future = ((FutureAdapter)f).getFuture();
//设置异步回调
future.setCallback(new ResponseCallback() {
public void done(Object rpcResult) {
//获得返回结果 并不是provider返回值哦
if (rpcResult == null) {
com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.logger.error(new IllegalStateException("invalid result value : null, expected " + Result.class.getName()));
} else if (!(rpcResult instanceof Result)) {
com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.logger.error(new IllegalStateException("invalid result type :" + rpcResult.getClass() + ", expected " + Result.class.getName()));
} else {
Result result = (Result)rpcResult;
//如果有异常触发异常回调
if (result.hasException()) {
//当前类是匿名类 com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this 为匿名类访问上层类对象的实例 就是FutureFilter实例
com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this.fireThrowCallback(invoker, invocation, result.getException());
} else {
//当前类是匿名类 com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this 为匿名类访问上层类对象的实例 就是FutureFilter实例
com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this.fireReturnCallback(invoker, invocation, result.getValue());
}
}
}
public void caught(Throwable exception) {
//异常回调
com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this.fireThrowCallback(invoker, invocation, exception);
}
});
}
}
private void fireInvokeCallback(Invoker<?> invoker, Invocation invocation) {
/**
* 获取我们配置的oinvoke的方法
* key为key为com.biz.soa.service.pagepromotion.frontend.PagePromotionService.prizeDraw.oninvoke.method
*/
Method onInvokeMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "oninvoke.method"));
/**
* 获取我们配置的oninvoke实例
* key为com.biz.soa.service.pagepromotion.frontend.PagePromotionService.prizeDraw.oninvoke.instance
*/
Object onInvokeInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "oninvoke.instance"));
if (onInvokeMethod != null || onInvokeInst != null) {
if (onInvokeMethod != null && onInvokeInst != null) {
if (!onInvokeMethod.isAccessible()) {
onInvokeMethod.setAccessible(true);
}
Object[] params = invocation.getArguments();
try {
//反射执行调用
onInvokeMethod.invoke(onInvokeInst, params);
} catch (InvocationTargetException var7) {
//调用失败会触发异常回调
this.fireThrowCallback(invoker, invocation, var7.getTargetException());
} catch (Throwable var8) {
//调用失败会触发异常回调
this.fireThrowCallback(invoker, invocation, var8);
}
} else {
throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onInvokeMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
}
}
}
private void fireReturnCallback(Invoker<?> invoker, Invocation invocation, Object result) {
Method onReturnMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "onreturn.method"));
Object onReturnInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "onreturn.instance"));
if (onReturnMethod != null || onReturnInst != null) {
if (onReturnMethod != null && onReturnInst != null) {
if (!onReturnMethod.isAccessible()) {
onReturnMethod.setAccessible(true);
}
Object[] args = invocation.getArguments();
Class<?>[] rParaTypes = onReturnMethod.getParameterTypes();
Object[] params;
if (rParaTypes.length > 1) {
if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
params = new Object[]{result, args};
} else {
params = new Object[args.length + 1];
params[0] = result;
System.arraycopy(args, 0, params, 1, args.length);
}
} else {
params = new Object[]{result};
}
try {
//反射调用
onReturnMethod.invoke(onReturnInst, params);
} catch (InvocationTargetException var10) {
this.fireThrowCallback(invoker, invocation, var10.getTargetException());
} catch (Throwable var11) {
this.fireThrowCallback(invoker, invocation, var11);
}
} else {
throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onReturnMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
}
}
}
private void fireThrowCallback(Invoker<?> invoker, Invocation invocation, Throwable exception) {
Method onthrowMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "onthrow.method"));
Object onthrowInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "onthrow.instance"));
if (onthrowMethod != null || onthrowInst != null) {
if (onthrowMethod != null && onthrowInst != null) {
if (!onthrowMethod.isAccessible()) {
onthrowMethod.setAccessible(true);
}
Class<?>[] rParaTypes = onthrowMethod.getParameterTypes();
if (rParaTypes[0].isAssignableFrom(exception.getClass())) {
try {
Object[] args = invocation.getArguments();
Object[] params;
if (rParaTypes.length > 1) {
if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
params = new Object[]{exception, args};
} else {
params = new Object[args.length + 1];
params[0] = exception;
System.arraycopy(args, 0, params, 1, args.length);
}
} else {
params = new Object[]{exception};
}
onthrowMethod.invoke(onthrowInst, params);
} catch (Throwable var9) {
logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), var9);
}
} else {
logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), exception);
}
} else {
throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onthrow callback config , but no such " + (onthrowMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
}
}
}
}
原理就是 获得我们对应的配置类 反射调用
DubboInvoker
但是有个疑惑 就是异步回调怎么实现的那么我们快invoker的实现 DubboInvoker
protected Result doInvoke(Invocation invocation) throws Throwable {
RpcInvocation inv = (RpcInvocation)invocation;
String methodName = RpcUtils.getMethodName(invocation);
inv.setAttachment("path", this.getUrl().getPath());
inv.setAttachment("version", this.version);
ExchangeClient currentClient;
if (this.clients.length == 1) {
currentClient = this.clients[0];
} else {
currentClient = this.clients[this.index.getAndIncrement() % this.clients.length];
}
try {
//是否是异步
boolean isAsync = RpcUtils.isAsync(this.getUrl(), invocation);
//里面取的配置的return 配合sent使用 默认是false <dubbo:method sent="true" return="true" async="true"
boolean isOneway = RpcUtils.isOneway(this.getUrl(), invocation);
int timeout = this.getUrl().getMethodParameter(methodName, "timeout", 1000);
//可以看出return优先级大于async
if (isOneway) {
/**
* 如果设置了sent=true,表示等待网络数据发出才返回,如果sent=false,只是将待发送数据发到IO写缓存区就返回。
*/
boolean isSent = this.getUrl().getMethodParameter(methodName, "sent", false);
currentClient.send(inv, isSent);
RpcContext.getContext().setFuture((Future)null);
return new RpcResult();
} else if (isAsync) {
//如果是异步则上下文设置一个Future对象并返回
ResponseFuture future = currentClient.request(inv, timeout);
RpcContext.getContext().setFuture(new FutureAdapter(future));
return new RpcResult();
} else {
RpcContext.getContext().setFuture((Future)null);
//默认实现 Future.get 所以是同步的
return (Result)currentClient.request(inv, timeout).get();
}
} catch (TimeoutException var9) {
throw new RpcException(2, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + this.getUrl() + ", cause: " + var9.getMessage(), var9);
} catch (RemotingException var10) {
throw new RpcException(1, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + this.getUrl() + ", cause: " + var10.getMessage(), var10);
}
}
Provider
ContextFilter
filter链条顶端 主要在当前上下文设置一些基础信息
@Activate(
group = {"provider"},
order = -10000
)
public class ContextFilter implements Filter {
public ContextFilter() {
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
Map<String, String> attachments = invocation.getAttachments();
if (attachments != null) {
//剔除一些参数
attachments = new HashMap((Map)attachments);
((Map)attachments).remove("path");
((Map)attachments).remove("group");
((Map)attachments).remove("version");
((Map)attachments).remove("dubbo");
((Map)attachments).remove("token");
((Map)attachments).remove("timeout");
((Map)attachments).remove("async");
}
//从线程缓存获取当前线程的RpcContext 记录一些请求信息
RpcContext.getContext().setInvoker(invoker).setInvocation(invocation).setLocalAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
if (attachments != null) {
//将剔除后的attachments设置到上下文
if (RpcContext.getContext().getAttachments() != null) {
RpcContext.getContext().getAttachments().putAll((Map)attachments);
} else {
RpcContext.getContext().setAttachments((Map)attachments);
}
}
//设置步骤只是设置一层代理 在构造参数从url添加一些信息
if (invocation instanceof RpcInvocation) {
((RpcInvocation)invocation).setInvoker(invoker);
}
Result var4;
try {
var4 = invoker.invoke(invocation);
} finally {
//线程缓存清除
RpcContext.removeContext();
}
return var4;
}
}
EchoFilter
回响测试主要用来检测服务是否正常(网络状态),单纯的检测网络情况的话其实不需要执行真正的业务逻辑的,所以通过Filter验证一下即可。
官方文档

consumer生成代理 强制实现了EchoService 我们强转为EchoService就能调用测试服务是否可用
/**
* 回声测试 用来校验服务是否可用 并不执行具体逻辑
*/
@Activate(
group = {"provider"},
order = -110000
)
public class EchoFilter implements Filter {
public EchoFilter() {
}
public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
/**
* 如果是回声测试 则只返回入参
*/
return (Result)(inv.getMethodName().equals("$echo")
&& inv.getArguments() != null
&& inv.getArguments().length == 1 ? new RpcResult(inv.getArguments()[0]) : invoker.invoke(inv));
}
}
ExecuteLimitFilter
例子
1.解决注解配置报错问题
参考:https://blog.csdn.net/xiao_jun_0820/article/details/81218440
/**
* 解决@Service注解配置parameters参数时无法将String[]转化成Map<String,String>的bug
* @author :
* @since*/
@Component
public static class ServiceParameterBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements PriorityOrdered {
@Override
public int getOrder() {
return PriorityOrdered.LOWEST_PRECEDENCE;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
// pvs.getPropertyValue("parameter")
if (bean instanceof ServiceBean) {
PropertyValue propertyValue = pvs.getPropertyValue("parameters");
ConversionService conversionService = getConversionService();
if (propertyValue != null && propertyValue.getValue() != null && conversionService.canConvert(propertyValue.getValue().getClass(), Map.class)) {
Map parameters = conversionService.convert(propertyValue.getValue(), Map.class);
propertyValue.setConvertedValue(parameters);
}
}
return pvs;
}
private ConversionService getConversionService() {
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new StringArrayToStringConverter());
conversionService.addConverter(new StringArrayToMapConverter());
return conversionService;
}
}
2.限流配置
/**
* @author liqiang
* @date 2019/10/15 19:33
* @Description:封装暴露前端的 业务处理
*/
@Service("frontPagePromotionService")
@com.alibaba.dubbo.config.annotation.Service(
parameters = {"prizeDraw.executes","1"}
)
public class PagePromotionServiceImpl extends AbstractBaseService implements PagePromotionService {
/**
* 用户根据活动抽奖
*
* @return
*/
@Transactional(rollbackFor = Exception.class)
public PrizeDrawResDto prizeDraw(PrizeDrawReqDto prizeDrawReqDto) throws Exception {
...
}
}
源码
/**
* 服务提供者限流
*/
@Activate(
group = {"provider"},
value = {"executes"}
)
public class ExecuteLimitFilter implements Filter {
public ExecuteLimitFilter() {
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
URL url = invoker.getUrl();
String methodName = invocation.getMethodName();
Semaphore executesLimit = null;
boolean acquireResult = false; //获取我们配置的executes
int max = url.getMethodParameter(methodName, "executes", 0);
if (max > 0) {
//获取当前请求的RpcStatus
RpcStatus count = RpcStatus.getStatus(url, invocation.getMethodName());
//获得信号量
executesLimit = count.getSemaphore(max);
//如果达到限流条件直接报错
if (executesLimit != null && !(acquireResult = executesLimit.tryAcquire())) {
throw new RpcException("Failed to invoke method " + invocation.getMethodName() + " in provider " + url + ", cause: The service using threads greater than <dubbo:service executes=\"" + max + "\" /> limited.");
}
}
long begin = System.currentTimeMillis();
boolean isSuccess = true;
RpcStatus.beginCount(url, methodName);
Result var12;
try {
Result result = invoker.invoke(invocation);
var12 = result;
} catch (Throwable var16) {
isSuccess = false;
if (var16 instanceof RuntimeException) {
throw (RuntimeException)var16;
}
throw new RpcException("unexpected exception when ExecuteLimitFilter", var16);
} finally {
RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, isSuccess);
if (acquireResult) {
//请求完成释放限流
executesLimit.release();
}
}
return var12;
}
}
ExceptionFilter
异常抛出规则
如果是 checked异常 则直接抛出; 如果是unchecked异常 但是在接口上有声明,也会直接抛出; 如果异常类和接口类在同一jar包里,直接抛出; 如果是 JDK自带的异常 ,直接抛出; 如果是 Dubbo的异常 ,直接抛出; 其余的都包装成RuntimeException然后抛出(避免异常在Client不能反序列化问题);
源码
@Activate(
group = {"provider"}
)
public class ExceptionFilter implements Filter {
private final Logger logger;
public ExceptionFilter() {
this(LoggerFactory.getLogger(com.alibaba.dubbo.rpc.filter.ExceptionFilter.class));
}
public ExceptionFilter(Logger logger) {
this.logger = logger;
}
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
try {
//执行invoke
Result result = invoker.invoke(invocation);
//判断是否有异常
if (result.hasException() && GenericService.class != invoker.getInterface()) {
try {
Throwable exception = result.getException();
//如果不是runtime异常直接返回
if (!(exception instanceof RuntimeException) && exception instanceof Exception) {
return result;
} else {
try {
Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
//获得方法上面声明的异常集合
Class<?>[] exceptionClassses = method.getExceptionTypes();
Class[] arr$ = exceptionClassses;
int len$ = exceptionClassses.length;
for(int i$ = 0; i$ < len$; ++i$) {
Class<?> exceptionClass = arr$[i$];
//如果异常等于声明的异常 直接返回 注意是equals
if (exception.getClass().equals(exceptionClass)) {
return result;
}
}
} catch (NoSuchMethodException var11) {
return result;
}
//找到这里表示并不是声明的异常 比如声明thow Exception 抛出空指针异常 才会到这里
this.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);
String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
//如果是其他jar包的异常 则包装成Runtime异常 抛出 避免客户端序列化失败问题
if (serviceFile != null && exceptionFile != null && !serviceFile.equals(exceptionFile)) {
String className = exception.getClass().getName();
if (!className.startsWith("java.") && !className.startsWith("javax.")) {
return (Result)(exception instanceof RpcException ? result : new RpcResult(new RuntimeException(StringUtils.toString(exception))));
} else {
return result;
}
} else {
return result;
}
}
} catch (Throwable var12) {
this.logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + var12.getClass().getName() + ": " + var12.getMessage(), var12);
return result;
}
} else {
return result;
}
} catch (RuntimeException var13) {
this.logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + var13.getClass().getName() + ": " + var13.getMessage(), var13);
throw var13;
}
}
}
dubbo-源码阅读之Filter默认实现的更多相关文章
- 【Dubbo源码阅读系列】之远程服务调用(上)
今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...
- 【Dubbo源码阅读系列】服务暴露之远程暴露
引言 什么叫 远程暴露 ?试着想象着这么一种场景:假设我们新增了一台服务器 A,专门用于发送短信提示给指定用户.那么问题来了,我们的 Message 服务上线之后,应该如何告知调用方服务器,服务器 A ...
- 【Dubbo源码阅读系列】服务暴露之本地暴露
在上一篇文章中我们介绍 Dubbo 自定义标签解析相关内容,其中我们自定义的 XML 标签 <dubbo:service /> 会被解析为 ServiceBean 对象(传送门:Dubbo ...
- 【Dubbo源码阅读系列】之 Dubbo SPI 机制
最近抽空开始了 Dubbo 源码的阅读之旅,希望可以通过写文章的方式记录和分享自己对 Dubbo 的理解.如果在本文出现一些纰漏或者错误之处,也希望大家不吝指出. Dubbo SPI 介绍 Java ...
- Dubbo源码阅读顺序
转载: https://blog.csdn.net/heroqiang/article/details/85340958 Dubbo源码解析之配置解析篇,主要内容是<dubbo:service/ ...
- Android源码阅读-Filter过滤器
Filter 顺便看看,Android中过滤器是怎么实现的? 注释中提到,Filter一般通过继承Filterable实现 具体实现 这是SimpleAdapter出现的一个过滤首字母item的一个过 ...
- Dubbo源码阅读-服务导出
Dubbo服务导出过程始于Spring容器发布刷新事件,Dubbo在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可分为三个部分,第一部分是前置工作,主要用于检查参数,组装URL.第二部分是导出服 ...
- dubbo源码阅读之服务导出
dubbo服务导出 常见的使用dubbo的方式就是通过spring配置文件进行配置.例如下面这样 <?xml version="1.0" encoding="UTF ...
- dubbo源码阅读之自适应扩展
自适应扩展机制 刚开始看代码,其实并不能很好地理解dubbo的自适应扩展机制的作用,我们不妨先把代码的主要逻辑过一遍,梳理一下,在了解了代码细节之后,回过头再来思考自适应扩展的作用,dubbo为什么要 ...
随机推荐
- 2018-2-13-win10-UWP-单元测试
title author date CreateTime categories win10 UWP 单元测试 lindexi 2018-2-13 17:23:3 +0800 2018-2-13 17: ...
- Python中dict的特点
dict的第一个特点是查找速度快,无论dict有10个元素还是10万个元素,查找速度都一样.而list的查找速度随着元素增加而逐渐下降. 不过dict的查找速度快不是没有代价的,dict的缺点是占用内 ...
- Jpa动态多表if多条件联合查询,并对查询结果进行分页
public Page<Map<String, Object>> resourceList(TeachingInfo teachingInfo, Pageable pageab ...
- SpringDataJpa全部依赖
<properties> <spring.version>4.2.4.RELEASE</spring.version> <hibernate.version& ...
- Linux系统之-TCP-IP链路层
一.基本 网络层协议的数据单元是 IP 数据报 ,而数据链路层的工作就是把网络层交下来的 IP 数据报 封装为 帧(frame)发送到链路上,以及把接收到的帧中的数据取出并上交给网络层. 为达到这一目 ...
- 探索Redis设计与实现9:数据库redisDb与键过期删除策略
本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...
- (转)Spring Boot干货系列:(四)开发Web应用之Thymeleaf篇
转:http://tengj.top/2017/03/13/springboot4/ 前言 Web开发是我们平时开发中至关重要的,这里就来介绍一下Spring Boot对Web开发的支持. 正文 Sp ...
- windows系统查看端口占用
netstat -ano #列出所用端口使用情况 netstat -aon|findstr "端口号" #查询指定端口 tasklist|findstr "PID&qu ...
- ylbtech-公司-滴滴出行:滴滴出行
ylbtech-公司-滴滴出行:滴滴出行 滴滴出行是涵盖出租车. 专车. 滴滴快车. 顺风车. 代驾及 大巴等多项业务在内的一站式出行平台,2015年9月9日由“滴滴打车”更名而来. 2月1日起, ...
- HTML-参考手册: HTML 颜色名
ylbtech-HTML-参考手册: HTML 颜色名 1.返回顶部 1. HTML 颜色名 目前所有浏览器都支持以下颜色名. 141个颜色名称是在HTML和CSS颜色规范定义的(17标准颜色,再加1 ...