SPI配置的默认实现

  1. cache=com.alibaba.dubbo.cache.filter.CacheFilter
  2. validation=com.alibaba.dubbo.validation.filter.ValidationFilter
  3. echo=com.alibaba.dubbo.rpc.filter.EchoFilter
  4. generic=com.alibaba.dubbo.rpc.filter.GenericFilter
  5. genericimpl=com.alibaba.dubbo.rpc.filter.GenericImplFilter
  6. token=com.alibaba.dubbo.rpc.filter.TokenFilter
  7. accesslog=com.alibaba.dubbo.rpc.filter.AccessLogFilter
  8. activelimit=com.alibaba.dubbo.rpc.filter.ActiveLimitFilter
  9. classloader=com.alibaba.dubbo.rpc.filter.ClassLoaderFilter
  10. context=com.alibaba.dubbo.rpc.filter.ContextFilter
  11. consumercontext=com.alibaba.dubbo.rpc.filter.ConsumerContextFilter
  12. exception=com.alibaba.dubbo.rpc.filter.ExceptionFilter
  13. executelimit=com.alibaba.dubbo.rpc.filter.ExecuteLimitFilter
  14. deprecated=com.alibaba.dubbo.rpc.filter.DeprecatedFilter
  15. compatible=com.alibaba.dubbo.rpc.filter.CompatibleFilter
  16. timeout=com.alibaba.dubbo.rpc.filter.TimeoutFilter
  17. trace=com.alibaba.dubbo.rpc.protocol.dubbo.filter.TraceFilter
  18. future=com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter
  19. monitor=com.alibaba.dubbo.monitor.support.MonitorFilter

Consumer

ConsumerContextFilter

记录一些基础信息到当前线程的PRCContext

  1. @Activate(
  2. group = {"consumer"},
  3. order = -10000
  4. )
  5. public class ConsumerContextFilter implements Filter {
  6. public ConsumerContextFilter() {
  7. }
  8.  
  9. public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
  10. /***
  11. * 从线程缓存获取本次RpcContext.getContext()
  12. * 设置一些本次请求的基础信息到RpcContext
  13. */
  14. RpcContext.getContext().setInvoker(invoker)
  15. .setInvocation(invocation)
  16. .setLocalAddress(NetUtils.getLocalHost(), 0)
  17. .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
  18. if (invocation instanceof RpcInvocation) {
  19. ((RpcInvocation)invocation).setInvoker(invoker);
  20. }
  21.  
  22. Result var3;
  23. try {
  24. /**
  25. * 客户端相关参数是根据 invocation传递给消费者的 可以打断点看 也可以自定义一些数据 比如traceId
  26. */
  27. var3 = invoker.invoke(invocation);
  28. } finally {
  29. RpcContext.getContext().clearAttachments();
  30. }
  31.  
  32. return var3;
  33. }
  34. }

ActiveLimitFilter

例子

同时只支持1的并发量

  1. <dubbo:method actives="1" ... />

源码

ActiveLimitFilter主要用于 限制同一个客户端对于一个服务端方法的并发调用量(客户端限流)。

  1. /**
  2. * 控制调用服务的并发量 限流
  3. * 同时支持多少请求
  4. */
  5. @Activate(
  6. group = {"consumer"},
  7. value = {"actives"}
  8. )
  9. public class ActiveLimitFilter implements Filter {
  10. public ActiveLimitFilter() {
  11. }
  12.  
  13. public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
  14. URL url = invoker.getUrl();
  15. String methodName = invocation.getMethodName();
  16. //获得 <dubbo:reference actives="1"> actives的数量
  17. int max = invoker.getUrl().getMethodParameter(methodName, "actives", 0);
  18. //获取当前service当前方法的请求数量
  19. RpcStatus count = RpcStatus.getStatus(invoker.getUrl(), invocation.getMethodName());
  20. long timeout;
  21. //配置并发控制大于0才写
  22. if (max > 0) {
  23. //获得当前方法的等待时间
  24. timeout = (long)invoker.getUrl().getMethodParameter(invocation.getMethodName(), "timeout", 0);
  25. long start = System.currentTimeMillis();
  26. long remain = timeout;
  27. //判断是否大于并发数 如果大于则等待
  28. int active = count.getActive();
  29. if (active >= max) {
  30. synchronized(count) {
  31. /**
  32. *1.while循环是有必要的
  33. * 当收到其他线程notify 获得执行权
  34. * 但是这个时候其他线程提前进入(active >= max) 判断为false获得执行权 count+1
  35. * 这个时候 还需要while判断是否还有空闲请求 否则继续wait
  36. *
  37. */
  38. while((active = count.getActive()) >= max) {
  39. try {
  40. //超时时间为 配置的超时时间
  41. count.wait(remain);
  42. } catch (InterruptedException var32) {
  43. ;
  44. }
  45.  
  46. long elapsed = System.currentTimeMillis() - start;
  47. remain = timeout - elapsed;
  48. //当其他线程通知等待线程执行 判断是否超时 如果超时了则不执行了
  49. if (remain <= 0L) {
  50. 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);
  51. }
  52. }
  53. }
  54. }
  55. }
  56.  
  57. boolean var28 = false;
  58.  
  59. Result var10;
  60. try {
  61. var28 = true;
  62. timeout = System.currentTimeMillis();
  63. //获得执行权的 count+1
  64. RpcStatus.beginCount(url, methodName);
  65.  
  66. try {
  67. //执行
  68. Result result = invoker.invoke(invocation);
  69. //执行完毕关闭
  70. RpcStatus.endCount(url, methodName, System.currentTimeMillis() - timeout, true);
  71. var10 = result;
  72. var28 = false;
  73. } catch (RuntimeException var31) {
  74. RpcStatus.endCount(url, methodName, System.currentTimeMillis() - timeout, false);
  75. throw var31;
  76. }
  77. } finally {
  78. if (var28) {
  79. if (max > 0) {
  80. //通知等待的线程执行
  81. synchronized(count) {
  82. count.notify();
  83. }
  84. }
  85.  
  86. }
  87. }
  88.  
  89. if (max > 0) {
  90. synchronized(count) {
  91. //通知等待的线程执行
  92. count.notify();
  93. }
  94. }
  95.  
  96. return var10;
  97. }
  98. }

FutureFilter

用于处理事件 异步回调 同步回调  异常回调

例子

1.自定义一个event接口

  1. /**
  2. * @author liqiang
  3. * @date 2019/11/28 10:34
  4. * @Description:定义一个抽象接口实现
  5. */
  6. public interface IEvent {
  7. /**
  8. * 从源码可以看到 传递的这2个参数
  9. *
  10. * @param throwable
  11. * @param args
  12. */
  13. public void onThrow(Throwable throwable, Object[] args);
  14.  
  15. /**
  16. * 从源码可以看到传递这2个参数
  17. * async为true表示异步回调
  18. * async为false 表示调用完成回调
  19. *
  20. * @param params
  21. */
  22. public void onReturn(Object[] params);
  23.  
  24. /**
  25. * 参数列表要跟执行列表一样
  26. * 这里参数列表不固定 应该抽出去 因为是demo 就写一起
  27. */
  28. public void onInvoke(PrizeDrawReqDto prizeDrawReqDto);
  29. }

2.实现类

  1. /**
  2. * @author liqiang
  3. * @date 2019/11/28 10:46
  4. * @Description: 回调实现类
  5. */
  6. public class PagePromotionServicePrizeDrawEvent implements IEvent {
  7. /**
  8. * 从源码可以看到 传递的这2个参数
  9. * 发生异常时回调
  10. * @param throwable
  11. * @param args
  12. */
  13. @Override
  14. public void onThrow(Throwable throwable, Object[] args) {
  15. System.out.println(String.format("异常回调,参数:%s",args.toString()));
  16. }
  17. /**
  18. * 从源码可以看到传递这2个参数
  19. * async为true表示异步回调
  20. * async为false 表示调用完成回调
  21. *
  22. * @param params
  23. */
  24. @Override
  25. public void onReturn(Object[] params) {
  26. System.out.println(String.format("onReturn回调:",params.toString()));
  27. }
  28.  
  29. /**
  30. * 参数列表要跟执行列表一样
  31. *执行前回调
  32. * @param prizeDrawReqDto
  33. */
  34. @Override
  35. public void onInvoke(PrizeDrawReqDto prizeDrawReqDto) {
  36. System.out.println(String.format("onInvoke执行前回调:",prizeDrawReqDto.toString()));
  37. }
  38. }

2.consumer配置

  1. <!--定义回调实现类的bean-->
  2. <bean id="pagePromotionServicePrizeDrawEvent" class="com.bozhi.notify.PagePromotionServicePrizeDrawEvent"></bean>
  3. <dubbo:reference id="frontendPagePromotionService"
  4. url="dubbo://127.0.0.1:23888/com.biz.soa.service.pagepromotion.frontend.PagePromotionService"
  5. interface="com.biz.soa.service.pagepromotion.frontend.PagePromotionService" check="false">
  6. <dubbo:method async="true" name="prizeDraw"
  7. onreturn="pagePromotionServicePrizeDrawEvent.onReturn"
  8. oninvoke="pagePromotionServicePrizeDrawEvent.onInvoke"
  9. onthrow="pagePromotionServicePrizeDrawEvent.onThrow"></dubbo:method>
  10. </dubbo:reference>

源码

  1. @Activate(
  2. group = {"consumer"}//消费端的过滤器
  3. )
  4. public class FutureFilter implements Filter {
  5. protected static final Logger logger = LoggerFactory.getLogger(com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.class);
  6.  
  7. public FutureFilter() {
  8. }
  9.  
  10. public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
  11. //在url后面获取是否是异步
  12. boolean isAsync = RpcUtils.isAsync(invoker.getUrl(), invocation);
  13. //执行调用前时间 onInvoker
  14. this.fireInvokeCallback(invoker, invocation);
  15. //执行invoke
  16. Result result = invoker.invoke(invocation);
  17. //判断是同步还是异步
  18. if (isAsync) {
  19. //处理异步调用回调
  20. this.asyncCallback(invoker, invocation);
  21. } else {
  22. //处理同步调用回调
  23. this.syncCallback(invoker, invocation, result);
  24. }
  25. return result;
  26. }
  27.  
  28. private void syncCallback(Invoker<?> invoker, Invocation invocation, Result result) {
  29. //是否发生异常 如果发生调用
  30. if (result.hasException()) {
  31. //调用异常回调
  32. this.fireThrowCallback(invoker, invocation, result.getException());
  33. } else {
  34. //触发onReturn
  35. this.fireReturnCallback(invoker, invocation, result.getValue());
  36. }
  37.  
  38. }
  39.  
  40. private void asyncCallback(final Invoker<?> invoker, final Invocation invocation) {
  41. //获取异步调用的Future
  42. Future<?> f = RpcContext.getContext().getFuture();
  43. //判断是否是FutureAdapter适配器
  44. if (f instanceof FutureAdapter) {
  45. ResponseFuture future = ((FutureAdapter)f).getFuture();
  46. //设置异步回调
  47. future.setCallback(new ResponseCallback() {
  48. public void done(Object rpcResult) {
  49. //获得返回结果 并不是provider返回值哦
  50. if (rpcResult == null) {
  51. com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.logger.error(new IllegalStateException("invalid result value : null, expected " + Result.class.getName()));
  52. } else if (!(rpcResult instanceof Result)) {
  53. com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.logger.error(new IllegalStateException("invalid result type :" + rpcResult.getClass() + ", expected " + Result.class.getName()));
  54. } else {
  55. Result result = (Result)rpcResult;
  56. //如果有异常触发异常回调
  57. if (result.hasException()) {
  58. //当前类是匿名类 com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this 为匿名类访问上层类对象的实例 就是FutureFilter实例
  59. com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this.fireThrowCallback(invoker, invocation, result.getException());
  60. } else {
  61. //当前类是匿名类 com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this 为匿名类访问上层类对象的实例 就是FutureFilter实例
  62. com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this.fireReturnCallback(invoker, invocation, result.getValue());
  63. }
  64.  
  65. }
  66. }
  67.  
  68. public void caught(Throwable exception) {
  69. //异常回调
  70. com.alibaba.dubbo.rpc.protocol.dubbo.filter.FutureFilter.this.fireThrowCallback(invoker, invocation, exception);
  71. }
  72. });
  73. }
  74.  
  75. }
  76.  
  77. private void fireInvokeCallback(Invoker<?> invoker, Invocation invocation) {
  78. /**
  79. * 获取我们配置的oinvoke的方法
  80. * key为key为com.biz.soa.service.pagepromotion.frontend.PagePromotionService.prizeDraw.oninvoke.method
  81. */
  82. Method onInvokeMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "oninvoke.method"));
  83. /**
  84. * 获取我们配置的oninvoke实例
  85. * key为com.biz.soa.service.pagepromotion.frontend.PagePromotionService.prizeDraw.oninvoke.instance
  86. */
  87. Object onInvokeInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "oninvoke.instance"));
  88. if (onInvokeMethod != null || onInvokeInst != null) {
  89. if (onInvokeMethod != null && onInvokeInst != null) {
  90. if (!onInvokeMethod.isAccessible()) {
  91. onInvokeMethod.setAccessible(true);
  92. }
  93.  
  94. Object[] params = invocation.getArguments();
  95.  
  96. try {
  97. //反射执行调用
  98. onInvokeMethod.invoke(onInvokeInst, params);
  99. } catch (InvocationTargetException var7) {
  100. //调用失败会触发异常回调
  101. this.fireThrowCallback(invoker, invocation, var7.getTargetException());
  102. } catch (Throwable var8) {
  103. //调用失败会触发异常回调
  104. this.fireThrowCallback(invoker, invocation, var8);
  105. }
  106.  
  107. } else {
  108. throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onInvokeMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
  109. }
  110. }
  111. }
  112.  
  113. private void fireReturnCallback(Invoker<?> invoker, Invocation invocation, Object result) {
  114. Method onReturnMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "onreturn.method"));
  115. Object onReturnInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "onreturn.instance"));
  116. if (onReturnMethod != null || onReturnInst != null) {
  117. if (onReturnMethod != null && onReturnInst != null) {
  118. if (!onReturnMethod.isAccessible()) {
  119. onReturnMethod.setAccessible(true);
  120. }
  121.  
  122. Object[] args = invocation.getArguments();
  123. Class<?>[] rParaTypes = onReturnMethod.getParameterTypes();
  124. Object[] params;
  125. if (rParaTypes.length > 1) {
  126. if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
  127. params = new Object[]{result, args};
  128. } else {
  129. params = new Object[args.length + 1];
  130. params[0] = result;
  131. System.arraycopy(args, 0, params, 1, args.length);
  132. }
  133. } else {
  134. params = new Object[]{result};
  135. }
  136.  
  137. try {
  138. //反射调用
  139. onReturnMethod.invoke(onReturnInst, params);
  140. } catch (InvocationTargetException var10) {
  141. this.fireThrowCallback(invoker, invocation, var10.getTargetException());
  142. } catch (Throwable var11) {
  143. this.fireThrowCallback(invoker, invocation, var11);
  144. }
  145.  
  146. } else {
  147. throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onReturnMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
  148. }
  149. }
  150. }
  151.  
  152. private void fireThrowCallback(Invoker<?> invoker, Invocation invocation, Throwable exception) {
  153. Method onthrowMethod = (Method)StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "onthrow.method"));
  154. Object onthrowInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), "onthrow.instance"));
  155. if (onthrowMethod != null || onthrowInst != null) {
  156. if (onthrowMethod != null && onthrowInst != null) {
  157. if (!onthrowMethod.isAccessible()) {
  158. onthrowMethod.setAccessible(true);
  159. }
  160.  
  161. Class<?>[] rParaTypes = onthrowMethod.getParameterTypes();
  162. if (rParaTypes[0].isAssignableFrom(exception.getClass())) {
  163. try {
  164. Object[] args = invocation.getArguments();
  165. Object[] params;
  166. if (rParaTypes.length > 1) {
  167. if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
  168. params = new Object[]{exception, args};
  169. } else {
  170. params = new Object[args.length + 1];
  171. params[0] = exception;
  172. System.arraycopy(args, 0, params, 1, args.length);
  173. }
  174. } else {
  175. params = new Object[]{exception};
  176. }
  177.  
  178. onthrowMethod.invoke(onthrowInst, params);
  179. } catch (Throwable var9) {
  180. logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), var9);
  181. }
  182. } else {
  183. logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), exception);
  184. }
  185.  
  186. } else {
  187. throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onthrow callback config , but no such " + (onthrowMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
  188. }
  189. }
  190. }
  191. }

原理就是 获得我们对应的配置类 反射调用

DubboInvoker

但是有个疑惑 就是异步回调怎么实现的那么我们快invoker的实现 DubboInvoker

  1. protected Result doInvoke(Invocation invocation) throws Throwable {
  2. RpcInvocation inv = (RpcInvocation)invocation;
  3. String methodName = RpcUtils.getMethodName(invocation);
  4. inv.setAttachment("path", this.getUrl().getPath());
  5. inv.setAttachment("version", this.version);
  6. ExchangeClient currentClient;
  7. if (this.clients.length == 1) {
  8. currentClient = this.clients[0];
  9. } else {
  10. currentClient = this.clients[this.index.getAndIncrement() % this.clients.length];
  11. }
  12.  
  13. try {
  14. //是否是异步
  15. boolean isAsync = RpcUtils.isAsync(this.getUrl(), invocation);
  16. //里面取的配置的return 配合sent使用 默认是false <dubbo:method sent="true" return="true" async="true"
  17. boolean isOneway = RpcUtils.isOneway(this.getUrl(), invocation);
  18. int timeout = this.getUrl().getMethodParameter(methodName, "timeout", 1000);
  19. //可以看出return优先级大于async
  20. if (isOneway) {
  21. /**
  22. * 如果设置了sent=true,表示等待网络数据发出才返回,如果sent=false,只是将待发送数据发到IO写缓存区就返回。
  23. */
  24. boolean isSent = this.getUrl().getMethodParameter(methodName, "sent", false);
  25. currentClient.send(inv, isSent);
  26. RpcContext.getContext().setFuture((Future)null);
  27. return new RpcResult();
  28. } else if (isAsync) {
  29. //如果是异步则上下文设置一个Future对象并返回
  30. ResponseFuture future = currentClient.request(inv, timeout);
  31. RpcContext.getContext().setFuture(new FutureAdapter(future));
  32. return new RpcResult();
  33. } else {
  34. RpcContext.getContext().setFuture((Future)null);
  35. //默认实现 Future.get 所以是同步的
  36. return (Result)currentClient.request(inv, timeout).get();
  37. }
  38. } catch (TimeoutException var9) {
  39. throw new RpcException(2, "Invoke remote method timeout. method: " + invocation.getMethodName() + ", provider: " + this.getUrl() + ", cause: " + var9.getMessage(), var9);
  40. } catch (RemotingException var10) {
  41. throw new RpcException(1, "Failed to invoke remote method: " + invocation.getMethodName() + ", provider: " + this.getUrl() + ", cause: " + var10.getMessage(), var10);
  42. }
  43. }

Provider

ContextFilter

filter链条顶端 主要在当前上下文设置一些基础信息

  1. @Activate(
  2. group = {"provider"},
  3. order = -10000
  4. )
  5. public class ContextFilter implements Filter {
  6. public ContextFilter() {
  7. }
  8.  
  9. public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
  10. Map<String, String> attachments = invocation.getAttachments();
  11. if (attachments != null) {
  12. //剔除一些参数
  13. attachments = new HashMap((Map)attachments);
  14. ((Map)attachments).remove("path");
  15. ((Map)attachments).remove("group");
  16. ((Map)attachments).remove("version");
  17. ((Map)attachments).remove("dubbo");
  18. ((Map)attachments).remove("token");
  19. ((Map)attachments).remove("timeout");
  20. ((Map)attachments).remove("async");
  21. }
  22. //从线程缓存获取当前线程的RpcContext 记录一些请求信息
  23. RpcContext.getContext().setInvoker(invoker).setInvocation(invocation).setLocalAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort());
  24. if (attachments != null) {
  25. //将剔除后的attachments设置到上下文
  26. if (RpcContext.getContext().getAttachments() != null) {
  27. RpcContext.getContext().getAttachments().putAll((Map)attachments);
  28. } else {
  29. RpcContext.getContext().setAttachments((Map)attachments);
  30. }
  31. }
  32.  
  33. //设置步骤只是设置一层代理 在构造参数从url添加一些信息
  34. if (invocation instanceof RpcInvocation) {
  35. ((RpcInvocation)invocation).setInvoker(invoker);
  36. }
  37.  
  38. Result var4;
  39. try {
  40. var4 = invoker.invoke(invocation);
  41. } finally {
  42. //线程缓存清除
  43. RpcContext.removeContext();
  44. }
  45.  
  46. return var4;
  47. }
  48. }

EchoFilter

回响测试主要用来检测服务是否正常(网络状态),单纯的检测网络情况的话其实不需要执行真正的业务逻辑的,所以通过Filter验证一下即可。

官方文档

consumer生成代理 强制实现了EchoService 我们强转为EchoService就能调用测试服务是否可用

  1. /**
  2. * 回声测试 用来校验服务是否可用 并不执行具体逻辑
  3. */
  4. @Activate(
  5. group = {"provider"},
  6. order = -110000
  7. )
  8. public class EchoFilter implements Filter {
  9. public EchoFilter() {
  10. }
  11.  
  12. public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException {
  13. /**
  14. * 如果是回声测试 则只返回入参
  15. */
  16. return (Result)(inv.getMethodName().equals("$echo")
  17. && inv.getArguments() != null
  18. && inv.getArguments().length == 1 ? new RpcResult(inv.getArguments()[0]) : invoker.invoke(inv));
  19. }
  20. }

ExecuteLimitFilter

例子

1.解决注解配置报错问题

参考:https://blog.csdn.net/xiao_jun_0820/article/details/81218440

  1. /**
  2. * 解决@Service注解配置parameters参数时无法将String[]转化成Map<String,String>的bug
  3. * @author :
  4. * @since*/
  5. @Component
  6. public static class ServiceParameterBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter implements PriorityOrdered {
  7.  
  8. @Override
  9. public int getOrder() {
  10. return PriorityOrdered.LOWEST_PRECEDENCE;
  11. }
  12.  
  13. @Override
  14. public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
  15. // pvs.getPropertyValue("parameter")
  16. if (bean instanceof ServiceBean) {
  17. PropertyValue propertyValue = pvs.getPropertyValue("parameters");
  18. ConversionService conversionService = getConversionService();
  19.  
  20. if (propertyValue != null && propertyValue.getValue() != null && conversionService.canConvert(propertyValue.getValue().getClass(), Map.class)) {
  21. Map parameters = conversionService.convert(propertyValue.getValue(), Map.class);
  22. propertyValue.setConvertedValue(parameters);
  23. }
  24. }
  25. return pvs;
  26. }
  27.  
  28. private ConversionService getConversionService() {
  29. DefaultConversionService conversionService = new DefaultConversionService();
  30. conversionService.addConverter(new StringArrayToStringConverter());
  31. conversionService.addConverter(new StringArrayToMapConverter());
  32. return conversionService;
  33. }
  34.  
  35. }

2.限流配置

  1. /**
  2. * @author liqiang
  3. * @date 2019/10/15 19:33
  4. * @Description:封装暴露前端的 业务处理
  5. */
  6. @Service("frontPagePromotionService")
  7. @com.alibaba.dubbo.config.annotation.Service(
  8. parameters = {"prizeDraw.executes","1"}
  9. )
  10. public class PagePromotionServiceImpl extends AbstractBaseService implements PagePromotionService {
  11. /**
  12. * 用户根据活动抽奖
  13. *
  14. * @return
  15. */
  16. @Transactional(rollbackFor = Exception.class)
  17. public PrizeDrawResDto prizeDraw(PrizeDrawReqDto prizeDrawReqDto) throws Exception {
  18. ...
  19. }
  20. }

源码

  1. /**
  2. * 服务提供者限流
  3. */
  4. @Activate(
  5. group = {"provider"},
  6. value = {"executes"}
  7. )
  8. public class ExecuteLimitFilter implements Filter {
  9. public ExecuteLimitFilter() {
  10. }
  11.  
  12. public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
  13. URL url = invoker.getUrl();
  14. String methodName = invocation.getMethodName();
  15. Semaphore executesLimit = null;
  16. boolean acquireResult = false; //获取我们配置的executes
  17. int max = url.getMethodParameter(methodName, "executes", 0);
  18. if (max > 0) {
  19. //获取当前请求的RpcStatus
  20. RpcStatus count = RpcStatus.getStatus(url, invocation.getMethodName());
  21. //获得信号量
  22. executesLimit = count.getSemaphore(max);
  23. //如果达到限流条件直接报错
  24. if (executesLimit != null && !(acquireResult = executesLimit.tryAcquire())) {
  25. throw new RpcException("Failed to invoke method " + invocation.getMethodName() + " in provider " + url + ", cause: The service using threads greater than <dubbo:service executes=\"" + max + "\" /> limited.");
  26. }
  27. }
  28.  
  29. long begin = System.currentTimeMillis();
  30. boolean isSuccess = true;
  31. RpcStatus.beginCount(url, methodName);
  32.  
  33. Result var12;
  34. try {
  35. Result result = invoker.invoke(invocation);
  36. var12 = result;
  37. } catch (Throwable var16) {
  38. isSuccess = false;
  39. if (var16 instanceof RuntimeException) {
  40. throw (RuntimeException)var16;
  41. }
  42.  
  43. throw new RpcException("unexpected exception when ExecuteLimitFilter", var16);
  44. } finally {
  45. RpcStatus.endCount(url, methodName, System.currentTimeMillis() - begin, isSuccess);
  46. if (acquireResult) {
  47. //请求完成释放限流
  48. executesLimit.release();
  49. }
  50.  
  51. }
  52.  
  53. return var12;
  54. }
  55. }

ExceptionFilter

异常抛出规则

  1. 如果是 checked异常 则直接抛出;
  2. 如果是unchecked异常 但是在接口上有声明,也会直接抛出;
  3. 如果异常类和接口类在同一jar包里,直接抛出;
  4. 如果是 JDK自带的异常 ,直接抛出;
  5. 如果是 Dubbo的异常 ,直接抛出;
  6. 其余的都包装成RuntimeException然后抛出(避免异常在Client不能反序列化问题);

源码

  1. @Activate(
  2. group = {"provider"}
  3. )
  4. public class ExceptionFilter implements Filter {
  5. private final Logger logger;
  6.  
  7. public ExceptionFilter() {
  8. this(LoggerFactory.getLogger(com.alibaba.dubbo.rpc.filter.ExceptionFilter.class));
  9. }
  10.  
  11. public ExceptionFilter(Logger logger) {
  12. this.logger = logger;
  13. }
  14.  
  15. public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
  16. try {
  17. //执行invoke
  18. Result result = invoker.invoke(invocation);
  19. //判断是否有异常
  20. if (result.hasException() && GenericService.class != invoker.getInterface()) {
  21. try {
  22. Throwable exception = result.getException();
  23. //如果不是runtime异常直接返回
  24. if (!(exception instanceof RuntimeException) && exception instanceof Exception) {
  25. return result;
  26. } else {
  27. try {
  28. Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes());
  29. //获得方法上面声明的异常集合
  30. Class<?>[] exceptionClassses = method.getExceptionTypes();
  31. Class[] arr$ = exceptionClassses;
  32. int len$ = exceptionClassses.length;
  33.  
  34. for(int i$ = 0; i$ < len$; ++i$) {
  35. Class<?> exceptionClass = arr$[i$];
  36. //如果异常等于声明的异常 直接返回 注意是equals
  37. if (exception.getClass().equals(exceptionClass)) {
  38. return result;
  39. }
  40. }
  41. } catch (NoSuchMethodException var11) {
  42. return result;
  43. }
  44. //找到这里表示并不是声明的异常 比如声明thow Exception 抛出空指针异常 才会到这里
  45. 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);
  46. String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface());
  47. String exceptionFile = ReflectUtils.getCodeBase(exception.getClass());
  48. //如果是其他jar包的异常 则包装成Runtime异常 抛出 避免客户端序列化失败问题
  49. if (serviceFile != null && exceptionFile != null && !serviceFile.equals(exceptionFile)) {
  50. String className = exception.getClass().getName();
  51. if (!className.startsWith("java.") && !className.startsWith("javax.")) {
  52. return (Result)(exception instanceof RpcException ? result : new RpcResult(new RuntimeException(StringUtils.toString(exception))));
  53. } else {
  54. return result;
  55. }
  56. } else {
  57. return result;
  58. }
  59. }
  60. } catch (Throwable var12) {
  61. 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);
  62. return result;
  63. }
  64. } else {
  65. return result;
  66. }
  67. } catch (RuntimeException var13) {
  68. 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);
  69. throw var13;
  70. }
  71. }
  72. }

dubbo-源码阅读之Filter默认实现的更多相关文章

  1. 【Dubbo源码阅读系列】之远程服务调用(上)

    今天打算来讲一讲 Dubbo 服务远程调用.笔者在开始看 Dubbo 远程服务相关源码的时候,看的有点迷糊.后来慢慢明白 Dubbo 远程服务的调用的本质就是动态代理模式的一种实现.本地消费者无须知道 ...

  2. 【Dubbo源码阅读系列】服务暴露之远程暴露

    引言 什么叫 远程暴露 ?试着想象着这么一种场景:假设我们新增了一台服务器 A,专门用于发送短信提示给指定用户.那么问题来了,我们的 Message 服务上线之后,应该如何告知调用方服务器,服务器 A ...

  3. 【Dubbo源码阅读系列】服务暴露之本地暴露

    在上一篇文章中我们介绍 Dubbo 自定义标签解析相关内容,其中我们自定义的 XML 标签 <dubbo:service /> 会被解析为 ServiceBean 对象(传送门:Dubbo ...

  4. 【Dubbo源码阅读系列】之 Dubbo SPI 机制

    最近抽空开始了 Dubbo 源码的阅读之旅,希望可以通过写文章的方式记录和分享自己对 Dubbo 的理解.如果在本文出现一些纰漏或者错误之处,也希望大家不吝指出. Dubbo SPI 介绍 Java ...

  5. Dubbo源码阅读顺序

    转载: https://blog.csdn.net/heroqiang/article/details/85340958 Dubbo源码解析之配置解析篇,主要内容是<dubbo:service/ ...

  6. Android源码阅读-Filter过滤器

    Filter 顺便看看,Android中过滤器是怎么实现的? 注释中提到,Filter一般通过继承Filterable实现 具体实现 这是SimpleAdapter出现的一个过滤首字母item的一个过 ...

  7. Dubbo源码阅读-服务导出

    Dubbo服务导出过程始于Spring容器发布刷新事件,Dubbo在接收到事件后,会立即执行服务导出逻辑.整个逻辑大致可分为三个部分,第一部分是前置工作,主要用于检查参数,组装URL.第二部分是导出服 ...

  8. dubbo源码阅读之服务导出

    dubbo服务导出 常见的使用dubbo的方式就是通过spring配置文件进行配置.例如下面这样 <?xml version="1.0" encoding="UTF ...

  9. dubbo源码阅读之自适应扩展

    自适应扩展机制 刚开始看代码,其实并不能很好地理解dubbo的自适应扩展机制的作用,我们不妨先把代码的主要逻辑过一遍,梳理一下,在了解了代码细节之后,回过头再来思考自适应扩展的作用,dubbo为什么要 ...

随机推荐

  1. Linux: 给右键菜单加一个“转换图片为jpg格式”

    Linux上通常都会安装imagemagick这个小巧但又异常强大的工具.这个软件提供了一系列很好用的功能.这里说一说如何使用它的convert命令转换图片为jpg格式,以及如何把它添加到Thunar ...

  2. Elasticsearch index

    POST/{index}/{type} Elasticsearch自动生成ID,自动生成的 ID 是 URL-safe. 基于 Base64 编码且长度为20个字符的 GUID 字符串. 这些 GUI ...

  3. foobar2000 频谱给我的win10 任务栏添加一点会动背景

    在任务栏右键,"任务栏设置",颜色 -> 透明效果, 然后 foobar2000 的 view -> layout -> Quick Setup,选择带有Visu ...

  4. css 设置背景图片透明

    最终效果: 背景图片css不变,再背景图片的里层元素设置css样式即可 opacity:0.4; filter:alpha(opacity=40); /* 针对 IE8 以及更早的版本 */

  5. Oracle查询用户所有表

    https://blog.csdn.net/wssiqi/article/details/44617197 Oracle查询用户所有表   下面为您介绍的语句用于实现Oracle查询用户所有表,如果您 ...

  6. 设置php的环境变量 php: command not found

    执行远程服务器上的某个脚本,却报错,提示php:command not found 找不到php命令 which php  结果是/usr/local/php/bin/php echo $PATH 结 ...

  7. Sql语法整理-图片版....

  8. python--有参装饰器、迭代器

    有参装饰器的引入: import time import random from functools import wraps def timmer(func): @wraps(func) def w ...

  9. 基于c语言数据结构+严蔚敏——线性表章节源码,利用Codeblocks编译通过

    白天没屌事,那我们就来玩玩线性表的实现吧,快要失业了,没饭吃了咋整哦 题目描述假设利用两个线性表LA和LB分别表示两个集合A和B(即:线性表中的数据元素即为集合中的成员),现要求一个新的集合A=A∪B ...

  10. win10 解决telnet不是内部或外部命令的方案

    1.Telnet用于远程操作互联网中的设备或终端计算机服务器,可以有效的减少现场操作的麻烦.因为设备或终端是遍布整个省或市,有的甚至是国外,如何高效的处理问题是当务之急,除了telnet还可以ssh使 ...