dubbo事件通知机制(1)
此文已由作者岳猛授权网易云社区发布。
欢迎访问网易云社区,了解更多网易技术产品运营经验。
dubbo事件通知机制:http://dubbo.io/books/dubbo-user-book/demos/events-notify.html
一、使用方式
两个服务:
DemoService:真正要调用的服务
Notify:事件通知服务(用在consumer端)
provider:
1 package com.alibaba.dubbo.demo;
2
3 public interface DemoService {
4 String sayHello(String name);
5 }
1 public class DemoServiceImpl implements DemoService {
2 @Override
3 public String sayHello(String name) {
4 throw new RpcException("ex, param: " + name);//测试onthrow方法
5 // return "Hello " + name;//测试onreturn方法
6 }
7 }
consumer:
通知服务:Notify
1 package com.alibaba.dubbo.demo.consumer.eventnotify;
2
3 public interface Notify {
4 void oninvoke(String name); // 调用之前
5 void onreturnWithoutParam(String result); // 调用之后
6 void onreturn(String result, String name); // 调用之后
7 void onthrow(Throwable ex, String name); // 出现异常
8 }
1 package com.alibaba.dubbo.demo.consumer.eventnotify;
2
3 public class NotifyService implements Notify {
4 @Override
5 public void oninvoke(String name) {
6 System.out.println("======oninvoke======, param: " + name);
7 }
8
9 @Override
10 public void onreturnWithoutParam(String result) {
11 System.out.println("======onreturn======, result: " + result);
12 }
13
14 @Override
15 public void onreturn(String result, String name) {
16 System.out.println("======onreturn======, param: " + name + ", result: " + result);
17 }
18
19 @Override
20 public void onthrow(Throwable ex, String name) {
21 System.out.println("======onthrow======, param: " + name + ", exception: " + ex.getMessage());
22 }
23 }
xml配置:
1 <bean id="notifyService" class="com.alibaba.dubbo.demo.consumer.eventnotify.NotifyService"/>
2 <dubbo:reference id="demoService" check="false" interface="com.alibaba.dubbo.demo.DemoService">
3 <dubbo:method name="sayHello" timeout="60000" oninvoke="notifyService.oninvoke" onreturn="notifyService.onreturnWithoutParam" onthrow="notifyService.onthrow"/>
4 </dubbo:reference>
之后就可以运行Consumer启动类,之后调用demoService.sayHello(String name)了。
注意:
oninvoke方法:
必须具有与真实的被调用方法sayHello相同的入参列表:例如,oninvoke(String name)
onreturn方法:
至少要有一个入参且第一个入参必须与sayHello的返回类型相同,接收返回结果:例如,onreturnWithoutParam(String result)
可以有多个参数,多个参数的情况下,第一个后边的所有参数都是用来接收sayHello入参的:例如, onreturn(String result, String name)
onthrow方法:
至少要有一个入参且第一个入参类型为Throwable或其子类,接收返回结果;例如,onthrow(Throwable ex)
可以有多个参数,多个参数的情况下,第一个后边的所有参数都是用来接收sayHello入参的:例如,onthrow(Throwable ex, String name)
如果是consumer在调用provider的过程中,出现异常时不会走onthrow方法的,onthrow方法只会在provider返回的RpcResult中含有Exception对象时,才会执行。(dubbo中下层服务的Exception会被放在响应RpcResult的exception对象中传递给上层服务)
二、源码解析
整个事件通知的逻辑都在FutureFilter中,来看一下源码:
1 /**
2 * EventFilter
3 */
4 @Activate(group = Constants.CONSUMER)
5 public class FutureFilter implements Filter {
6
7 protected static final Logger logger = LoggerFactory.getLogger(FutureFilter.class);
8
9 public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
10 final boolean isAsync = RpcUtils.isAsync(invoker.getUrl(), invocation);
11
12 //1 调用服务之前:执行xxxService.oninvoke方法
13 fireInvokeCallback(invoker, invocation);
14 //2 调用服务
15 Result result = invoker.invoke(invocation);
16 //3 调用服务之后
17 if (isAsync) {
18 asyncCallback(invoker, invocation);
19 } else {
20 syncCallback(invoker, invocation, result); 21 }
22 //4 返回调用结果
23 return result;
24 }
25
26 private void syncCallback(final Invoker<?> invoker, final Invocation invocation, final Result result) {
27 if (result.hasException()) {
28 //3.1 调用服务之后:如果返回结果异常信息(注意:如果是consumer自己throw的异常,会在2的时候直接抛走,不会走到这里),直接执行xxxService.onthrow方法
29 fireThrowCallback(invoker, invocation, result.getException());
30 } else {
31 //3.2 调用服务之后:如果返回值正常,执行xxxService.onreturn方法
32 fireReturnCallback(invoker, invocation, result.getValue());
33 }
34 }
35
36 private void asyncCallback(final Invoker<?> invoker, final Invocation invocation) {
37 Future<?> f = RpcContext.getContext().getFuture();
38 if (f instanceof FutureAdapter) {
39 ResponseFuture future = ((FutureAdapter<?>) f).getFuture();
40 // 3.1 调用服务之后:设置回调ResponseCallback对象到DefaultFuture中,当provider返回响应时,执行DefaultFuture.doReceived方法,该方法会调用ResponseCallback对象的done或者caught方法
41 future.setCallback(new ResponseCallback() {
42 public void done(Object rpcResult) {
43 if (rpcResult == null) {
44 logger.error(new IllegalStateException("invalid result value : null, expected " + Result.class.getName()));
45 return;
46 }
47 ///must be rpcResult
48 if (!(rpcResult instanceof Result)) {
49 logger.error(new IllegalStateException("invalid result type :" + rpcResult.getClass() + ", expected " + Result.class.getName()));
50 return;
51 }
52 Result result = (Result) rpcResult;
53 if (result.hasException()) {
54 fireThrowCallback(invoker, invocation, result.getException());
55 } else {
56 fireReturnCallback(invoker, invocation, result.getValue());
57 }
58 }
59
60 public void caught(Throwable exception) {
61 fireThrowCallback(invoker, invocation, exception);
62 }
63 });
64 }
65 }
66
67 /**
68 * 反射执行xxxService.oninvoke方法:必须具有与真实的被调用方法sayHello相同的入参列表。
69 */
70 private void fireInvokeCallback(final Invoker<?> invoker, final Invocation invocation) {
71 final Method onInvokeMethod = (Method) StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_INVOKE_METHOD_KEY));
72 final Object onInvokeInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_INVOKE_INSTANCE_KEY));
73
74 if (onInvokeMethod == null && onInvokeInst == null) {
75 return;
76 }
77 if (onInvokeMethod == null || onInvokeInst == null) {
78 throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onInvokeMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
79 }
80 if (onInvokeMethod != null && !onInvokeMethod.isAccessible()) {
81 onInvokeMethod.setAccessible(true);
82 }
83 // 获取真实方法sayHello传入的参数
84 Object[] params = invocation.getArguments();
85 try {
86 onInvokeMethod.invoke(onInvokeInst, params);
87 } catch (InvocationTargetException e) {
88 fireThrowCallback(invoker, invocation, e.getTargetException());
89 } catch (Throwable e) {
90 fireThrowCallback(invoker, invocation, e);
91 }
92 }
93
94 /**
95 * 反射执行xxxService.onreturn方法:至少要有一个入参,接收返回结果
96 */
97 private void fireReturnCallback(final Invoker<?> invoker, final Invocation invocation, final Object result) {
98 final Method onReturnMethod = (Method) StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_RETURN_METHOD_KEY));
99 final Object onReturnInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_RETURN_INSTANCE_KEY));
100
101 //not set onreturn callback
102 if (onReturnMethod == null && onReturnInst == null) {
103 return;
104 }
105
106 if (onReturnMethod == null || onReturnInst == null) {
107 throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onReturnMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
108 }
109 if (onReturnMethod != null && !onReturnMethod.isAccessible()) {
110 onReturnMethod.setAccessible(true);
111 }
112
113 Object[] args = invocation.getArguments();
114 Object[] params;
115 Class<?>[] rParaTypes = onReturnMethod.getParameterTypes();
116 if (rParaTypes.length > 1) {
117 // onreturn(xx, Object[]) 两个参数:第一个参数与真实方法sayHello方法返回结果类型相同,第二个接收所有的真实请求参数
118 if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
119 params = new Object[2];
120 params[0] = result; // 真实方法的执行结果
121 params[1] = args; // 真实方法sayHello传入的参数
122 // onreturn(xx, Object... args) 多个参数:第一个参数与真实方法sayHello方法返回结果类型相同,后边几个接收所有的真实请求参数
123 } else {
124 params = new Object[args.length + 1];
125 params[0] = result; // 真实方法的执行结果
126 System.arraycopy(args, 0, params, 1, args.length);
127 }
128 } else {
129 // onreturn(xx) 只有一个参数:接收返回执行结果
130 params = new Object[]{result}; // 执行结果
131 }
132 try {
133 onReturnMethod.invoke(onReturnInst, params);
134 } catch (InvocationTargetException e) {
135 fireThrowCallback(invoker, invocation, e.getTargetException());
136 } catch (Throwable e) {
137 fireThrowCallback(invoker, invocation, e);
138 }
139 }
140
141 /**
更多网易技术、产品、运营经验分享请点击。
相关文章:
【推荐】 Dubbo与Hadoop RPC的区别
【推荐】 git subrepo
dubbo事件通知机制(1)的更多相关文章
- 9.5 dubbo事件通知机制
dubbo事件通知机制:http://dubbo.io/books/dubbo-user-book/demos/events-notify.html 一.使用方式 两个服务: DemoService: ...
- dubbo事件通知机制 (2)
此文已由作者赵计刚授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 142 * 反射执行xxxService.onthrow方法:至少要有一个入参且第一个入参类型为T ...
- spring事件通知机制详解
优势 解耦 对同一种事件有多种处理方式 不干扰主线(main line) 起源 要讲spring的事件通知机制,就要先了解一下spring中的这些接口和抽象类: ApplicationEventPub ...
- muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制
目录 muduo网络库学习笔记(四) 通过eventfd实现的事件通知机制 eventfd的使用 eventfd系统函数 使用示例 EventLoop对eventfd的封装 工作时序 runInLoo ...
- Spring事件通知机制
在上图中,调用 getApplicationEventMulticaster()方法,该方法返回的ApplicationEventMulticaster类型的对象applicationEventMul ...
- 重叠I/O之事件通知
在 Winsock 中,重叠 I/O(Overlapped I/O)模型能达到更佳的系统性能,高于select模型.异步选择和事件选择三种.重叠模型的基本设计原理便是让应用程序使 用一个重叠的数据 ...
- Android应用程序组件Content Provider的共享数据更新通知机制分析
文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/6985171 在Android系统中,应用程序组 ...
- 如何扩展分布式日志组件(Exceptionless)的Webhook事件通知类型?
写在前面 从上一篇博客高并发.低延迟之C#玩转CPU高速缓存(附示例)到现在又有几个月没写博客了,啥也不说,变得越来越懒了,懒惰产生了拖延后遗症. 最近一周升级了微服务项目使用的分布式日志组件Exce ...
- 深入理解nodejs的异步IO与事件模块机制
node为什么要使用异步I/O 异步I/O的技术方案:轮询技术 node的异步I/O nodejs事件环 一.node为什么要使用异步I/O 异步最先诞生于操作系统的底层,在底层系统中,异步通过信号量 ...
随机推荐
- Yii 引入js css jquery 执行操作
在布局中引用通用到js,或者css: <?php Yii::app()->clientScript->registerCoreScript('jquery');?> //注意 ...
- sqlplus 方式连接 远程数据库
方式一:简易连接,不用进行网络配置,其实就是tnsname.ora文件,但只支持oracle10G以上.命令:sqlplus 用户名/密码@ip地址[:端口]/service_name [as sys ...
- TCP接入层的负载均衡、高可用、扩展性架构
一.web-server的负载均衡 互联网架构中,web-server接入一般使用nginx来做反向代理,实施负载均衡.整个架构分三层: 上游调用层,一般是browser或者APP 中间反向代理层,n ...
- 7.25 8figting!
TEXT 87 Fund management基金管理 A Miller's tale 米勒传奇(陈继龙编译) Dec 7th 2006 From The Economist print edit ...
- 迷你MVVM框架 avalonjs 学习教程1、引入avalon
avalon是国内最强大的MVVM框架,没有之一,虽然淘宝KISSY团队也搞了两个MVVM框架,但都无疾而终.其他的MVVM框架都没几个.也只有外国人与像我这样闲的架构师才有时间钻研这东西.我很早之前 ...
- go 算法
题目: 请实现一个算法,确定一个字符串的所有字符[是否全都不同].这里我们要求[不允许使用额外的存储结构].给定一个string,请返回一个bool值,true代表所有字符全都不同,false代表存在 ...
- 323. Number of Connected Components in an Undirected Graph按照线段添加的并查集
[抄题]: Given n nodes labeled from 0 to n - 1 and a list of undirected edges (each edge is a pair of n ...
- JDeveloper 开发环境配置
JDeveloper 开发环境配置 程序员的基础教程:菜鸟程序员
- mybatis框架入门程序:演示通过mybatis实现数据库的模糊查询操作
1. mybatis的基本准备操作见我的上一篇博文:https://www.cnblogs.com/wyhluckdog/p/10149480.html 2. 根据用户名查询用户信息: (1)映射文件 ...
- 使用jedis2.8.0连接redis
下载了最新的jedis客户端jedis2.8.0,在网上找了找jedis使用连接池的工具类,拿来发现都是低版本的jedis写法: returnResource(); returnBrokenResou ...