Dubbo过滤器原理解析
一. 自定义过滤器配置:
dubbo filter可能是我们使用dubbo时最经常自定义的。通常用作一些公共处理,比如公共的日志打印让代码更简洁,和如上示例的通用异常结果处理等,配置过程如下:
1. 定义过滤器实现org.apache.dubbo.rpc.Filter接口,并在类上增加@Activate注解激活。
注解常用参数:
group:URL(org.apache.dubbo.common.URL)中的分组如果匹配则激活,如provider、consumer
value:URL中如果包含该key值则激活
before:填写扩展点列表,表示哪些扩展点要在本扩展点之前激活
after:表示哪些扩展点要在本扩展点之前激活
order:优先级(执行顺序)
过滤器类示例:
1 @Activate( 2 group = {CommonConstants.PROVIDER}, 3 order = 1 4 ) 5 public class DubboExceptionFilter implements Filter, Filter.Listener { 6 7 @Override 8 public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { 9 return invoker.invoke(invocation); 10 } 11 12 @Override 13 public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { 14 } 15 16 @Override 17 public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) { 18 } 19 20 }
2. 在配置文件 META-INF/dubbo/org.apache.dubbo.rpc.Filter 中增加:
xxFilter = 自定义Filter
例:
dubboExceptionFilter=com.wenzq.filter.DubboExceptionFilter
使用dubbo提供的SPI扩展机制,扩展很便捷。
3. 如果需要排除指定过滤器,使其不生效,可在xml中配置filter名称前加"-"
例:
<dubbo:provider filter="-dubboLogFilter" ... ... /> <dubbo:consumer filter="-dubboLogFilter" ... ... /> <dubbo:service id="xxxProvider" interface="com.xxx.xxx" filter="-dubboLogFilter" ... ... /> <dubbo:reference id="xxxConsumer" interface="com.xxx.xxx" filter="-dubboLogFilter" ... ... />
二. Dubbo过滤器原理:
使用起来这么便捷,那么过滤器是如何加载配置和执行的呢,接下来根据提供者、消费者过滤器一一分析。
Provider:
dubbo暴露服务时序大致如下:
从上图可看出服务暴露调用顺序:
ServiceConfig.export -> RegistryProtocol.export -> DubboProtocol.export
此处我们重点关注DubboProtocol,注意DubboProtocol为包装后的增强实现(dubbo的SPI扩展点自适应机制,此处简单类比成spring的AOP,详细了解SPI机制可参考 官方文档),调用DubboProtocol时实际调用为:
ProtocolListenerWrapper -> ProtocolFilterWrapper -> QosProtocolWrapper -> DubboProtocol
构建过滤器链就在ProtocolListenerWrapper.export方法中完成,相关源码如下:
1 @Override 2 public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException { 3 if (UrlUtils.isRegistry(invoker.getUrl())) { 4 return protocol.export(invoker); 5 } 6 // 构建过滤器链并暴露 7 return protocol.export(buildInvokerChain(invoker, SERVICE_FILTER_KEY, CommonConstants.PROVIDER)); 8 } 9 10 /** 11 * 构建过滤器链 12 */ 13 private static <T> Invoker<T> buildInvokerChain(final Invoker<T> invoker, String key, String group) { 14 Invoker<T> last = invoker; 15 // 基于dubbo SPI active机制加载filter列表 16 List<Filter> filters = ExtensionLoader.getExtensionLoader(Filter.class).getActivateExtension(invoker.getUrl(), key, group); 17 18 if (!filters.isEmpty()) { 19 for (int i = filters.size() - 1; i >= 0; i--) { 20 final Filter filter = filters.get(i); 21 // 新建过滤器节点,并放入当前节点 22 last = new FilterNode<T>(invoker, last, filter); 23 } 24 } 25 26 return last; 27 }
其中入参invoker为实际调用,通过ExtensionLoader获取过滤器列表(已根据order排序),并以invoker作为最后一个节点倒序构建过滤器链。
接下来看过滤器链节点执行过程:每个节点执行invoke方法时,内部实际调用节点持有filter的invoke方法,执行时传入下一个节点。当前filter逻辑执行完毕后,内部会手动调用下一个节点的invoke方法,依次向下调用直到最终invoker,最终invoker执行完毕返回结果至顶层节点,调用完成,所以过滤器链最终调用顺序为:Filter1 -> Filter2 -> Filter3 ... ... -> Invoker。
可以看出调用链的每个节点都为invoker增加了功能,属装饰器模式的一种实现。
1 class FilterNode<T> implements Invoker<T>{ 2 3 @Override 4 public Result invoke(Invocation invocation) throws RpcException { 5 Result asyncResult; 6 try { 7 // 执行invoke传入下一个节点 8 asyncResult = filter.invoke(next, invocation); 9 } catch (Exception e) { 10 if (filter instanceof ListenableFilter) { 11 ListenableFilter listenableFilter = ((ListenableFilter) filter); 12 try { 13 Filter.Listener listener = listenableFilter.listener(invocation); 14 if (listener != null) { 15 listener.onError(e, invoker, invocation); 16 } 17 } finally { 18 listenableFilter.removeListener(invocation); 19 } 20 } else if (filter instanceof Filter.Listener) { 21 Filter.Listener listener = (Filter.Listener) filter; 22 listener.onError(e, invoker, invocation); 23 } 24 throw e; 25 } finally { 26 27 } 28 return asyncResult.whenCompleteWithContext((r, t) -> { 29 if (filter instanceof ListenableFilter) { 30 ListenableFilter listenableFilter = ((ListenableFilter) filter); 31 Filter.Listener listener = listenableFilter.listener(invocation); 32 try { 33 if (listener != null) { 34 if (t == null) { 35 listener.onResponse(r, invoker, invocation); 36 } else { 37 listener.onError(t, invoker, invocation); 38 } 39 } 40 } finally { 41 listenableFilter.removeListener(invocation); 42 } 43 } else if (filter instanceof Filter.Listener) { 44 Filter.Listener listener = (Filter.Listener) filter; 45 if (t == null) { 46 listener.onResponse(r, invoker, invocation); 47 } else { 48 listener.onError(t, invoker, invocation); 49 } 50 } 51 }); 52 } 53 54 /** 55 * 省略部分代码 ... ... 56 */ 57 58 }
Consumer:
dubbo服务引用时序大致如下:
可以看出调用顺序:
RefrenceConfig.refer -> RegistryProtocol.refer -> DubboProtocol.refer
DubboProtocol与提供者同理,构建过滤器链在ProtocolListenerWrapper.refer方法中完成。
buildInvokerChain方法与服务提供者相同,过滤器调用也是类似的。
1 @Override 2 public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException { 3 if (UrlUtils.isRegistry(url)) { 4 return protocol.refer(type, url); 5 } 6 return buildInvokerChain(protocol.refer(type, url), REFERENCE_FILTER_KEY, CommonConstants.CONSUMER); 7 }
三. 原生过滤器:
dubbo原生提供多个过滤器,配置在META-INF/dubbo/internal/org.apache.dubbo.rpc.filter文件中(详情见表格,绿色代表提供者/消费者生效,值为order)。接下来简要讲解过滤器用途和主要源码,篇幅原因挑选部分过滤器讲解。
说明:本文源码基于dubbo 2.7.16-release
dubbo原生过滤器
提供者:
过滤器调用顺序:EchoFilter -> ClassLoaderFilter -> GenericFilter -> ContextFilter -> TraceFilter -> TimeoutFilter -> MonitorFilter -> ExceptionFilter
EchoFilter
用于回音测试,所谓回音测试就是Provider返回Consumer请求数据。
1 @Activate(group = CommonConstants.PROVIDER, order = -110000) 2 public class EchoFilter implements Filter { 3 4 @Override 5 public Result invoke(Invoker<?> invoker, Invocation inv) throws RpcException { 6 // 判断方法名是否$echo && 参数长度是否等于1 7 if (inv.getMethodName().equals($ECHO) && inv.getArguments() != null && inv.getArguments().length == 1) { 8 // 将传入参数返回(回声) 9 return AsyncRpcResult.newDefaultAsyncResult(inv.getArguments()[0], inv); 10 } 11 return invoker.invoke(inv); 12 } 13 14 }
ClassLoaderFilter
类加载过滤器,诈一看代码有点懵,切换线程的类加载器干啥?因为当前线程类加载器可能与Invoker接口类加载器不一致,但是当前线程中需要获取 Invoker 的类加载器中的一些 Class,以防出现 ClassNotFoundException异常。
1 @Activate(group = CommonConstants.PROVIDER, order = -30000) 2 public class ClassLoaderFilter implements Filter { 3 4 @Override 5 public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { 6 // 获取当前线程原类加载器 7 ClassLoader ocl = Thread.currentThread().getContextClassLoader(); 8 // 切换当前线程的类加载器为服务接口的类加载器 9 Thread.currentThread().setContextClassLoader(invoker.getInterface().getClassLoader()); 10 try { 11 // 执行invoker 12 return invoker.invoke(invocation); 13 } finally { 14 // 完成后,切换当前线程的类加载器为原类加载器 15 Thread.currentThread().setContextClassLoader(ocl); 16 } 17 } 18 19 }
ContextFilter
服务提供者上下文过滤器,对应消费者上下文过滤器为ConsumerContextFilter。讲解ContextFilter就不得不谈谈RpcContext,dubbo提供了这个上下文用于给提供者/消费者隐式传递参数,并且只在当前调用链上生效。用途如:分布式链路追踪,traceId、spanId传递等。
消费端设置参数:
1 RpcContext.getContext().getObjectAttachments().put("consumerInfo","params");
服务端读取参数:
1 Object providerInfo = RpcContext.getServerContext().getObjectAttachments().get("consumerInfo");
反之服务端设置参数、消费端获取参数亦可。
1 @Activate(group = PROVIDER, order = Integer.MIN_VALUE) 2 public class ContextFilter implements Filter, Filter.Listener { 3 4 private static final String TAG_KEY = "dubbo.tag"; 5 6 private static final Set<String> UNLOADING_KEYS; 7 8 static { 9 UNLOADING_KEYS = new HashSet<>(128); 10 UNLOADING_KEYS.add(PATH_KEY); 11 UNLOADING_KEYS.add(INTERFACE_KEY); 12 UNLOADING_KEYS.add(GROUP_KEY); 13 UNLOADING_KEYS.add(VERSION_KEY); 14 UNLOADING_KEYS.add(DUBBO_VERSION_KEY); 15 UNLOADING_KEYS.add(TOKEN_KEY); 16 UNLOADING_KEYS.add(TIMEOUT_KEY); 17 UNLOADING_KEYS.add(TIMEOUT_ATTACHMENT_KEY); 18 19 // Remove async property to avoid being passed to the following invoke chain. 20 UNLOADING_KEYS.add(ASYNC_KEY); 21 UNLOADING_KEYS.add(TAG_KEY); 22 UNLOADING_KEYS.add(FORCE_USE_TAG); 23 } 24 25 @Override 26 public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { 27 Map<String, Object> attachments = invocation.getObjectAttachments(); 28 // 新建attachments 29 if (attachments != null) { 30 Map<String, Object> newAttach = new HashMap<>(attachments.size()); 31 for (Map.Entry<String, Object> entry : attachments.entrySet()) { 32 String key = entry.getKey(); 33 if (!UNLOADING_KEYS.contains(key)) { 34 newAttach.put(key, entry.getValue()); 35 } 36 } 37 attachments = newAttach; 38 } 39 40 // 获取并设置RpcContext 41 RpcContext context = RpcContext.getContext(); 42 context.setInvoker(invoker) 43 .setInvocation(invocation) 44 .setLocalAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort()); 45 String remoteApplication = (String) invocation.getAttachment(REMOTE_APPLICATION_KEY); 46 if (StringUtils.isNotEmpty(remoteApplication)) { 47 context.setRemoteApplicationName(remoteApplication); 48 } else { 49 context.setRemoteApplicationName((String) context.getAttachment(REMOTE_APPLICATION_KEY)); 50 } 51 52 long timeout = RpcUtils.getTimeout(invocation, -1); 53 if (timeout != -1) { 54 context.set(TIME_COUNTDOWN_KEY, TimeoutCountDown.newCountDown(timeout, TimeUnit.MILLISECONDS)); 55 } 56 57 // 设置RpcContext设置/添加attachments 58 if (attachments != null) { 59 if (context.getObjectAttachments() != null) { 60 context.getObjectAttachments().putAll(attachments); 61 } else { 62 context.setObjectAttachments(attachments); 63 } 64 } 65 // 设置RpcInvocation的invoker 66 if (invocation instanceof RpcInvocation) { 67 ((RpcInvocation) invocation).setInvoker(invoker); 68 } 69 70 try { 71 // 设置执行后不清除上下文 72 context.clearAfterEachInvoke(false); 73 return invoker.invoke(invocation); 74 } finally { 75 // 设置执行后清除上下文 76 context.clearAfterEachInvoke(true); 77 // 并发场景下必须从当前线程移除RPCContext,所以同一线程每次调用都重新创建上下文 78 RpcContext.removeContext(true); 79 RpcContext.removeServerContext(); 80 } 81 } 82 83 @Override 84 public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { 85 // 传递attachments到结果 86 appResponse.addObjectAttachments(RpcContext.getServerContext().getObjectAttachments()); 87 } 88 89 @Override 90 public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) { 91 92 } 93 }
TimeOutFilter
超时过滤器
1 @Activate(group = CommonConstants.PROVIDER) 2 public class TimeoutFilter implements Filter, Filter.Listener { 3 4 private static final Logger logger = LoggerFactory.getLogger(TimeoutFilter.class); 5 6 @Override 7 public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { 8 return invoker.invoke(invocation); 9 } 10 11 @Override 12 public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { 13 // 从上下文中获取超时计时器 14 Object obj = RpcContext.getContext().get(TIME_COUNTDOWN_KEY); 15 if (obj != null) { 16 TimeoutCountDown countDown = (TimeoutCountDown) obj; 17 // 判断是否超时过期 18 if (countDown.isExpired()) { 19 // 超时情况,清空response 20 ((AppResponse) appResponse).clear(); 21 if (logger.isWarnEnabled()) { 22 // 输出警告日志 23 logger.warn("invoke timed out. method: " + invocation.getMethodName() + " arguments: " + 24 Arrays.toString(invocation.getArguments()) + " , url is " + invoker.getUrl() + 25 ", invoke elapsed " + countDown.elapsedMillis() + " ms."); 26 } 27 } 28 } 29 } 30 31 @Override 32 public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) { 33 34 } 35 }
MonitorFilter
监控过滤器,用于采集请求成功数、失败数、吞吐量、当前并发数、接口响应时长等。配置monitor后,MonitorFilter将采集监控信息并完成上报。
配置示例:
<dubbo:monitor address="dubbo://127.0.0.1:10880" />
1 @Activate(group = {PROVIDER, CONSUMER}) 2 public class MonitorFilter implements Filter, Filter.Listener { 3 4 private static final Logger logger = LoggerFactory.getLogger(MonitorFilter.class); 5 private static final String MONITOR_FILTER_START_TIME = "monitor_filter_start_time"; 6 private static final String MONITOR_REMOTE_HOST_STORE = "monitor_remote_host_store"; 7 8 /** 9 * The Concurrent counter 10 */ 11 private final ConcurrentMap<String, AtomicInteger> concurrents = new ConcurrentHashMap<String, AtomicInteger>(); 12 13 /** 14 * The MonitorFactory 15 */ 16 private MonitorFactory monitorFactory; 17 18 public void setMonitorFactory(MonitorFactory monitorFactory) { 19 this.monitorFactory = monitorFactory; 20 } 21 22 @Override 23 public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { 24 if (invoker.getUrl().hasParameter(MONITOR_KEY)) { 25 invocation.put(MONITOR_FILTER_START_TIME, System.currentTimeMillis()); 26 invocation.put(MONITOR_REMOTE_HOST_STORE, RpcContext.getContext().getRemoteHost()); 27 // 获取计数器+1 28 getConcurrent(invoker, invocation).incrementAndGet(); // count up 29 } 30 // 执行invoker 31 return invoker.invoke(invocation); 32 } 33 34 private AtomicInteger getConcurrent(Invoker<?> invoker, Invocation invocation) { 35 String key = invoker.getInterface().getName() + "." + invocation.getMethodName(); 36 return concurrents.computeIfAbsent(key, k -> new AtomicInteger()); 37 } 38 39 @Override 40 public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) { 41 if (invoker.getUrl().hasParameter(MONITOR_KEY)) { 42 collect(invoker, invocation, result, (String) invocation.get(MONITOR_REMOTE_HOST_STORE), (long) invocation.get(MONITOR_FILTER_START_TIME), false); 43 // 获取计数器-1 44 getConcurrent(invoker, invocation).decrementAndGet(); // count down 45 } 46 } 47 48 @Override 49 public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) { 50 if (invoker.getUrl().hasParameter(MONITOR_KEY)) { 51 collect(invoker, invocation, null, (String) invocation.get(MONITOR_REMOTE_HOST_STORE), (long) invocation.get(MONITOR_FILTER_START_TIME), true); 52 // 获取计数器-1 53 getConcurrent(invoker, invocation).decrementAndGet(); // count down 54 } 55 } 56 57 private void collect(Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) { 58 try { 59 URL monitorUrl = invoker.getUrl().getUrlParameter(MONITOR_KEY); 60 // 通过监控工厂获取监控对象 61 Monitor monitor = monitorFactory.getMonitor(monitorUrl); 62 if (monitor == null) { 63 return; 64 } 65 URL statisticsURL = createStatisticsUrl(invoker, invocation, result, remoteHost, start, error); 66 monitor.collect(statisticsURL); 67 } catch (Throwable t) { 68 logger.warn("Failed to monitor count service " + invoker.getUrl() + ", cause: " + t.getMessage(), t); 69 } 70 } 71 72 private URL createStatisticsUrl(Invoker<?> invoker, Invocation invocation, Result result, String remoteHost, long start, boolean error) { 73 // ---- service statistics ---- 74 // 计算调用耗时 75 long elapsed = System.currentTimeMillis() - start; 76 // 当前并发数量 77 int concurrent = getConcurrent(invoker, invocation).get(); 78 String application = invoker.getUrl().getParameter(APPLICATION_KEY); 79 // 接口名称 80 String service = invoker.getInterface().getName(); 81 // 方法名称 82 String method = RpcUtils.getMethodName(invocation); 83 // 分组信息 84 String group = invoker.getUrl().getParameter(GROUP_KEY); 85 // 版本信息 86 String version = invoker.getUrl().getParameter(VERSION_KEY); 87 88 int localPort; 89 String remoteKey, remoteValue; 90 if (CONSUMER_SIDE.equals(invoker.getUrl().getParameter(SIDE_KEY))) { 91 // 消费者时 92 localPort = 0; 93 remoteKey = MonitorService.PROVIDER; 94 remoteValue = invoker.getUrl().getAddress(); 95 } else { 96 // 提供者时 97 localPort = invoker.getUrl().getPort(); 98 remoteKey = MonitorService.CONSUMER; 99 remoteValue = remoteHost; 100 } 101 String input = "", output = ""; 102 if (invocation.getAttachment(INPUT_KEY) != null) { 103 input = invocation.getAttachment(INPUT_KEY); 104 } 105 if (result != null && result.getAttachment(OUTPUT_KEY) != null) { 106 output = result.getAttachment(OUTPUT_KEY); 107 } 108 // 返回统计URL 109 return new URL(COUNT_PROTOCOL, NetUtils.getLocalHost(), localPort, service + PATH_SEPARATOR + method, MonitorService.APPLICATION, application, MonitorService.INTERFACE, service, MonitorService.METHOD, method, remoteKey, remoteValue, error ? MonitorService.FAILURE : MonitorService.SUCCESS, "1", MonitorService.ELAPSED, String.valueOf(elapsed), MonitorService.CONCURRENT, String.valueOf(concurrent), INPUT_KEY, input, OUTPUT_KEY, output, GROUP_KEY, group, VERSION_KEY, version); 110 } 111 112 113 }
ExceptionFilter
异常处理过滤器
1 @Activate(group = CommonConstants.PROVIDER) 2 public class ExceptionFilter implements Filter, Filter.Listener { 3 private Logger logger = LoggerFactory.getLogger(ExceptionFilter.class); 4 5 @Override 6 public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { 7 return invoker.invoke(invocation); 8 } 9 10 @Override 11 public void onResponse(Result appResponse, Invoker<?> invoker, Invocation invocation) { 12 // 判断是否包含异常 13 if (appResponse.hasException() && GenericService.class != invoker.getInterface()) { 14 try { 15 Throwable exception = appResponse.getException(); 16 17 // 1. 非运行时异常且是检查型异常时,直接抛出 18 if (!(exception instanceof RuntimeException) && (exception instanceof Exception)) { 19 return; 20 } 21 // 2. 判断接口声明中是否抛出目标异常,是则直接抛出 22 try { 23 Method method = invoker.getInterface().getMethod(invocation.getMethodName(), invocation.getParameterTypes()); 24 Class<?>[] exceptionClasses = method.getExceptionTypes(); 25 for (Class<?> exceptionClass : exceptionClasses) { 26 if (exception.getClass().equals(exceptionClass)) { 27 return; 28 } 29 } 30 } catch (NoSuchMethodException e) { 31 return; 32 } 33 34 // 接口声明中没有包含目标异常,打印ERROR日志 35 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); 36 37 // 3. 如果异常类和接口类型在同一jar中,直接抛出 38 String serviceFile = ReflectUtils.getCodeBase(invoker.getInterface()); 39 String exceptionFile = ReflectUtils.getCodeBase(exception.getClass()); 40 if (serviceFile == null || exceptionFile == null || serviceFile.equals(exceptionFile)) { 41 return; 42 } 43 // 4. 根据异常类包名前缀判断是否jdk异常,是则抛出 44 String className = exception.getClass().getName(); 45 if (className.startsWith("java.") || className.startsWith("javax.")) { 46 return; 47 } 48 // 5. 判断是否dubbo异常,是则抛出 49 if (exception instanceof RpcException) { 50 return; 51 } 52 53 // 6. 包装成RuntimeException抛出(填充异常内容) 54 appResponse.setException(new RuntimeException(StringUtils.toString(exception))); 55 } catch (Throwable e) { 56 logger.warn("Fail to ExceptionFilter when called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e); 57 } 58 } 59 } 60 61 @Override 62 public void onError(Throwable e, Invoker<?> invoker, Invocation invocation) { 63 logger.error("Got unchecked and undeclared exception which called by " + RpcContext.getContext().getRemoteHost() + ". service: " + invoker.getInterface().getName() + ", method: " + invocation.getMethodName() + ", exception: " + e.getClass().getName() + ": " + e.getMessage(), e); 64 } 65 66 public void setLogger(Logger logger) { 67 this.logger = logger; 68 } 69 }
消费者:
消费者过滤器调用顺序:ConsumerContextFilter->FutureFilter->MonitorFilter->GenericImplFilter(仅限泛化调用)
ConsumerContextFilter
服务消费者上下文过滤器
1 @Activate(group = CONSUMER, order = -10000) 2 public class ConsumerContextFilter implements Filter { 3 4 @Override 5 public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException { 6 // 获取并设置context 7 RpcContext context = RpcContext.getContext(); 8 context.setInvoker(invoker) 9 .setInvocation(invocation) 10 .setLocalAddress(NetUtils.getLocalHost(), 0) 11 .setRemoteAddress(invoker.getUrl().getHost(), invoker.getUrl().getPort()) 12 .setRemoteApplicationName(invoker.getUrl().getParameter(REMOTE_APPLICATION_KEY)) 13 .setAttachment(REMOTE_APPLICATION_KEY, invoker.getUrl().getParameter(APPLICATION_KEY)); 14 // 设置RpcInvocation的invoker 15 if (invocation instanceof RpcInvocation) { 16 ((RpcInvocation) invocation).setInvoker(invoker); 17 } 18 19 // 获取超时计时器(此处为用户最终配置超时时间) 20 Object countDown = context.get(TIME_COUNTDOWN_KEY); 21 if (countDown != null) { 22 TimeoutCountDown timeoutCountDown = (TimeoutCountDown) countDown; 23 // 如果超时返回超时异常结果 24 if (timeoutCountDown.isExpired()) { 25 return AsyncRpcResult.newDefaultAsyncResult(new RpcException(RpcException.TIMEOUT_TERMINATE, 26 "No time left for making the following call: " + invocation.getServiceName() + "." 27 + invocation.getMethodName() + ", terminate directly."), invocation); 28 } 29 } 30 // 调用invoker并返回 31 return invoker.invoke(invocation); 32 } 33 34 }
MonitorFilter
同提供者
FutureFilter
FutureFilter调用之前、调用之后、出现异常时,会触发 oninvoke、onreturn、onthrow 三个事件,可以配置当事件发生时,通知对应类的对应方法。
详细可参考:官方示例
1 @Activate(group = CommonConstants.CONSUMER) 2 public class FutureFilter implements Filter, Filter.Listener { 3 4 protected static final Logger logger = LoggerFactory.getLogger(FutureFilter.class); 5 6 @Override 7 public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException { 8 fireInvokeCallback(invoker, invocation); 9 return invoker.invoke(invocation); 10 } 11 12 @Override 13 public void onResponse(Result result, Invoker<?> invoker, Invocation invocation) { 14 if (result.hasException()) { 15 fireThrowCallback(invoker, invocation, result.getException()); 16 } else { 17 fireReturnCallback(invoker, invocation, result.getValue()); 18 } 19 } 20 21 @Override 22 public void onError(Throwable t, Invoker<?> invoker, Invocation invocation) { 23 fireThrowCallback(invoker, invocation, t); 24 } 25 26 private void fireInvokeCallback(final Invoker<?> invoker, final Invocation invocation) { 27 // 获取异步方法MethodInfo 28 final AsyncMethodInfo asyncMethodInfo = getAsyncMethodInfo(invoker, invocation); 29 if (asyncMethodInfo == null) { 30 return; 31 } 32 // 获取回调方法、回调实例 33 final Method onInvokeMethod = asyncMethodInfo.getOninvokeMethod(); 34 final Object onInvokeInst = asyncMethodInfo.getOninvokeInstance(); 35 36 if (onInvokeMethod == null && onInvokeInst == null) { 37 return; 38 } 39 if (onInvokeMethod == null || onInvokeInst == null) { 40 throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a oninvoke callback config , but no such " + (onInvokeMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl()); 41 } 42 // 修改方法访问权限 43 ReflectUtils.makeAccessible(onInvokeMethod); 44 // 获取调用入参 45 Object[] params = invocation.getArguments(); 46 try { 47 // 调用回调方法(反射) 48 onInvokeMethod.invoke(onInvokeInst, params); 49 } catch (InvocationTargetException e) { 50 // 捕获异常调用异常处理方法fireThrowCallback 51 fireThrowCallback(invoker, invocation, e.getTargetException()); 52 } catch (Throwable e) { 53 fireThrowCallback(invoker, invocation, e); 54 } 55 } 56 57 private void fireReturnCallback(final Invoker<?> invoker, final Invocation invocation, final Object result) { 58 // 获取异步方法MethodInfo 59 final AsyncMethodInfo asyncMethodInfo = getAsyncMethodInfo(invoker, invocation); 60 if (asyncMethodInfo == null) { 61 return; 62 } 63 // 获取回调方法、回调实例 64 final Method onReturnMethod = asyncMethodInfo.getOnreturnMethod(); 65 final Object onReturnInst = asyncMethodInfo.getOnreturnInstance(); 66 67 if (onReturnMethod == null && onReturnInst == null) { 68 return; 69 } 70 71 if (onReturnMethod == null || onReturnInst == null) { 72 throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onReturnMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl()); 73 } 74 // 修改方法访问权限 75 ReflectUtils.makeAccessible(onReturnMethod); 76 // 获取调用入参 77 Object[] args = invocation.getArguments(); 78 Object[] params; 79 Class<?>[] rParaTypes = onReturnMethod.getParameterTypes(); 80 // 判断回调方法入参是否大于1 81 if (rParaTypes.length > 1) { 82 // 如果参数数量为2且第二个参数为Object数组,则1设置调用结果,2设置调用入参 83 if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) { 84 params = new Object[2]; 85 params[0] = result; 86 params[1] = args; 87 } else { 88 // 否则1设置调用结果,后续顺序设置入参 89 params = new Object[args.length + 1]; 90 params[0] = result; 91 System.arraycopy(args, 0, params, 1, args.length); 92 } 93 } else { 94 // 参数数量为1,直接赋值调用结果 95 params = new Object[]{result}; 96 } 97 try { 98 // 调用回调方法(反射) 99 onReturnMethod.invoke(onReturnInst, params); 100 } catch (InvocationTargetException e) { 101 // 捕获异常调用异常处理方法fireThrowCallback 102 fireThrowCallback(invoker, invocation, e.getTargetException()); 103 } catch (Throwable e) { 104 fireThrowCallback(invoker, invocation, e); 105 } 106 } 107 108 // 核心代码与fireReturnCallback一致,不赘述 109 private void fireThrowCallback(final Invoker<?> invoker, final Invocation invocation, final Throwable exception) { 110 final AsyncMethodInfo asyncMethodInfo = getAsyncMethodInfo(invoker, invocation); 111 if (asyncMethodInfo == null) { 112 return; 113 } 114 115 final Method onthrowMethod = asyncMethodInfo.getOnthrowMethod(); 116 final Object onthrowInst = asyncMethodInfo.getOnthrowInstance(); 117 118 if (onthrowMethod == null && onthrowInst == null) { 119 return; 120 } 121 if (onthrowMethod == null || onthrowInst == null) { 122 throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onthrow callback config , but no such " + (onthrowMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl()); 123 } 124 ReflectUtils.makeAccessible(onthrowMethod); 125 Class<?>[] rParaTypes = onthrowMethod.getParameterTypes(); 126 if (rParaTypes[0].isAssignableFrom(exception.getClass())) { 127 try { 128 Object[] args = invocation.getArguments(); 129 Object[] params; 130 131 if (rParaTypes.length > 1) { 132 if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) { 133 params = new Object[2]; 134 params[0] = exception; 135 params[1] = args; 136 } else { 137 params = new Object[args.length + 1]; 138 params[0] = exception; 139 System.arraycopy(args, 0, params, 1, args.length); 140 } 141 } else { 142 params = new Object[]{exception}; 143 } 144 onthrowMethod.invoke(onthrowInst, params); 145 } catch (Throwable e) { 146 logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), e); 147 } 148 } else { 149 logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), exception); 150 } 151 } 152 153 private AsyncMethodInfo getAsyncMethodInfo(Invoker<?> invoker, Invocation invocation) { 154 AsyncMethodInfo asyncMethodInfo = (AsyncMethodInfo) invocation.get(ASYNC_METHOD_INFO); 155 if (asyncMethodInfo != null) { 156 return asyncMethodInfo; 157 } 158 159 ConsumerModel consumerModel = ApplicationModel.getConsumerModel(invoker.getUrl().getServiceKey()); 160 if (consumerModel == null) { 161 return null; 162 } 163 164 String methodName = invocation.getMethodName(); 165 if (methodName.equals($INVOKE)) { 166 methodName = (String) invocation.getArguments()[0]; 167 } 168 169 // 返回AsyncMethodInfo(初始化:ReferenceConfig.init -> AbstractConfig.convertMethodConfig2AsyncInfo) 170 return consumerModel.getAsyncInfo(methodName); 171 } 172 173 }
转自:https://blog.csdn.net/gllqyqwz/article/details/126340679
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示