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

 

posted @ 2022-10-20 16:22  Boblim  阅读(672)  评论(0编辑  收藏  举报