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为什么要 ...
随机推荐
- Linux: 给右键菜单加一个“转换图片为jpg格式”
Linux上通常都会安装imagemagick这个小巧但又异常强大的工具.这个软件提供了一系列很好用的功能.这里说一说如何使用它的convert命令转换图片为jpg格式,以及如何把它添加到Thunar ...
- Elasticsearch index
POST/{index}/{type} Elasticsearch自动生成ID,自动生成的 ID 是 URL-safe. 基于 Base64 编码且长度为20个字符的 GUID 字符串. 这些 GUI ...
- foobar2000 频谱给我的win10 任务栏添加一点会动背景
在任务栏右键,"任务栏设置",颜色 -> 透明效果, 然后 foobar2000 的 view -> layout -> Quick Setup,选择带有Visu ...
- css 设置背景图片透明
最终效果: 背景图片css不变,再背景图片的里层元素设置css样式即可 opacity:0.4; filter:alpha(opacity=40); /* 针对 IE8 以及更早的版本 */
- Oracle查询用户所有表
https://blog.csdn.net/wssiqi/article/details/44617197 Oracle查询用户所有表 下面为您介绍的语句用于实现Oracle查询用户所有表,如果您 ...
- 设置php的环境变量 php: command not found
执行远程服务器上的某个脚本,却报错,提示php:command not found 找不到php命令 which php 结果是/usr/local/php/bin/php echo $PATH 结 ...
- Sql语法整理-图片版....
- python--有参装饰器、迭代器
有参装饰器的引入: import time import random from functools import wraps def timmer(func): @wraps(func) def w ...
- 基于c语言数据结构+严蔚敏——线性表章节源码,利用Codeblocks编译通过
白天没屌事,那我们就来玩玩线性表的实现吧,快要失业了,没饭吃了咋整哦 题目描述假设利用两个线性表LA和LB分别表示两个集合A和B(即:线性表中的数据元素即为集合中的成员),现要求一个新的集合A=A∪B ...
- win10 解决telnet不是内部或外部命令的方案
1.Telnet用于远程操作互联网中的设备或终端计算机服务器,可以有效的减少现场操作的麻烦.因为设备或终端是遍布整个省或市,有的甚至是国外,如何高效的处理问题是当务之急,除了telnet还可以ssh使 ...