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为什么要 ...
随机推荐
- onLaunch与onLoad同步获取用户数据
前言 在开发项目的时候遇到从全局获取用户信息,逻辑是从app.js中的onLauch获取,page页面的onLoad拿到数据填充到页面.遇到的问题是onLauch与onLoad是异步的,没办法从页面判 ...
- elasticsearch Mapping使用自定义分词器
创建索引及配置分析器 PUT /my_index { "settings": { "analysis": { "char_filter": ...
- Codeforces 356D 倍增优化背包
题目链接:http://codeforces.com/contest/356/problem/D 思路(官方题解):http://codeforces.com/blog/entry/9210 此题需要 ...
- python 数组元素个数
list=[1,2,3,{1,4,5,6,7}] print(len(list)) 输出4
- 【leetcode】948. Bag of Tokens
题目如下: You have an initial power P, an initial score of 0 points, and a bag of tokens. Each token can ...
- Linux系统之-介绍,主要特性
Linux是一套免费使用和自由传播的类Unix操作系统,是一个基于POSIX和UNIX的多用户.多任务.支持多线程和多CPU的操作系统.它能运行主要的UNIX工具软件.应用程序和网络协议.它支持32位 ...
- [NOIP模拟测试30]题解
A.Return 出题人大概是怕自己的中文十级没人知道,所以写了这么一个***题面.可能又觉得这题太水怕全场A掉后自己面子过不去,于是又故意把输出格式说的含糊不清.(鬼知道"那么输出-1&q ...
- bootstrap的模态框的使用
bootstrap的模态框 如果只想单独使用模态框功能,可以单独引入modal.js,和bootstrap的css,在bootstrap的包中,可引入bootstrap.js. 用法 通过data属性 ...
- 6、基于highcharts实现的线性拟合,计算部分在java中实现,画的是正态概率图
1.坐标点类 package cn.test.domain; public class Point { double x; double y; public Point(){ } public Poi ...
- C++ STL rope 可持久化平衡树 (可持久化数组)
官方文档好像 GG 了. rope 不属于标准 STL,属于扩展 STL,来自 pb_ds 库 (Policy-Based Data Structures). 基本操作: #include <e ...