9.5dubbo事件通知机制

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

9.5dubbo事件通知机制
⼀、使⽤⽅式
两个服务:
DemoService:真正要调⽤的服务
Notify:事件通知服务(⽤在consumer端)
provider:
1package com.alibaba.dubbo.demo;
2
3public interface DemoService {
4 String sayHello(String name);
5 }
1public class DemoServiceImpl implements DemoService {
2 @Override
3public String sayHello(String name) {
4throw new RpcException("ex, param: " + name);//测试onthrow⽅法
5// return "Hello " + name;//测试onreturn⽅法
6 }
7 }
consumer:
通知服务:Notify
1package com.alibaba.dubbo.demo.consumer.eventnotify;
2
3public interface Notify {
4void oninvoke(String name); // 调⽤之前
5void onreturnWithoutParam(String result); // 调⽤之后
6void onreturn(String result, String name); // 调⽤之后
7void onthrow(Throwable ex, String name); // 出现异常
8 }
1package com.alibaba.dubbo.demo.consumer.eventnotify;
2
3public class NotifyService implements Notify {
4 @Override
5public void oninvoke(String name) {
6 System.out.println("======oninvoke======, param: " + name);
7 }
8
9 @Override
10public void onreturnWithoutParam(String result) {
11 System.out.println("======onreturn======, result: " + result);
12 }
13
14 @Override
15public void onreturn(String result, String name) {
16 System.out.println("======onreturn======, param: " + name + ", result: " + result);
17 }
18
19 @Override
20public 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)
5public class FutureFilter implements Filter {
6
7protected static final Logger logger = LoggerFactory.getLogger(FutureFilter.class);
8
9public Result invoke(final Invoker<?> invoker, final Invocation invocation) throws RpcException {
10final 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 调⽤服务之后
17if (isAsync) {
18 asyncCallback(invoker, invocation);
19 } else {
20 syncCallback(invoker, invocation, result);
21 }
22//4 返回调⽤结果
23return result;
24 }
25
26private void syncCallback(final Invoker<?> invoker, final Invocation invocation, final Result result) {
27if (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
36private void asyncCallback(final Invoker<?> invoker, final Invocation invocation) {
37 Future<?> f = RpcContext.getContext().getFuture();
38if (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() {
42public void done(Object rpcResult) {
43if (rpcResult == null) {
44 logger.error(new IllegalStateException("invalid result value : null, expected " + Result.class.getName()));
45return;
46 }
47///must be rpcResult
48if (!(rpcResult instanceof Result)) {
49 logger.error(new IllegalStateException("invalid result type :" + rpcResult.getClass() + ", expected " + Result.class.getName()));
50return;
51 }
52 Result result = (Result) rpcResult;
53if (result.hasException()) {
54 fireThrowCallback(invoker, invocation, result.getException());
55 } else {
56 fireReturnCallback(invoker, invocation, result.getValue());
57 }
58 }
59
60public void caught(Throwable exception) {
61 fireThrowCallback(invoker, invocation, exception);
62 }
63 });
64 }
65 }
66
67/**
68 * 反射执⾏xxxService.oninvoke⽅法:必须具有与真实的被调⽤⽅法sayHello相同的⼊参列表。

69*/
70private void fireInvokeCallback(final Invoker<?> invoker, final Invocation invocation) {
71final Method onInvokeMethod = (Method) StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_INVOKE_METHOD_KEY));
72final Object onInvokeInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_INVOKE_INSTANCE_KEY));
73
74if (onInvokeMethod == null && onInvokeInst == null) {
75return;
76 }
77if (onInvokeMethod == null || onInvokeInst == null) {
78throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onInvokeMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl());
79 }
80if (onInvokeMethod != null && !onInvokeMethod.isAccessible()) {
81 onInvokeMethod.setAccessible(true);
82 }
83// 获取真实⽅法sayHello传⼊的参数
84 Object[] params = invocation.getArguments();
85try {
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*/
97private void fireReturnCallback(final Invoker<?> invoker, final Invocation invocation, final Object result) {
98final Method onReturnMethod = (Method) StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_RETURN_METHOD_KEY));
99final Object onReturnInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_RETURN_INSTANCE_KEY));
100
101//not set onreturn callback
102if (onReturnMethod == null && onReturnInst == null) {
103return;
104 }
105
106if (onReturnMethod == null || onReturnInst == null) {
107throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onreturn callback config , but no such " + (onReturnMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl()); 108 }
109if (onReturnMethod != null && !onReturnMethod.isAccessible()) {
110 onReturnMethod.setAccessible(true);
111 }
112
113 Object[] args = invocation.getArguments();
114 Object[] params;
115 Class<?>[] rParaTypes = onReturnMethod.getParameterTypes();
116if (rParaTypes.length > 1) {
117// onreturn(xx, Object[]) 两个参数:第⼀个参数与真实⽅法sayHello⽅法返回结果类型相同,第⼆个接收所有的真实请求参数
118if (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 }
132try {
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/**
142 * 反射执⾏xxxService.onthrow⽅法:⾄少要有⼀个⼊参且第⼀个⼊参类型为Throwable或其⼦类,接收返回结果
143*/
144private void fireThrowCallback(final Invoker<?> invoker, final Invocation invocation, final Throwable exception) {
145final Method onthrowMethod = (Method) StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_THROW_METHOD_KEY));
146final Object onthrowInst = StaticContext.getSystemContext().get(StaticContext.getKey(invoker.getUrl(), invocation.getMethodName(), Constants.ON_THROW_INSTANCE_KEY));
147
148//onthrow callback not configured
149if (onthrowMethod == null && onthrowInst == null) {
150return;
151 }
152if (onthrowMethod == null || onthrowInst == null) {
153throw new IllegalStateException("service:" + invoker.getUrl().getServiceKey() + " has a onthrow callback config , but no such " + (onthrowMethod == null ? "method" : "instance") + " found. url:" + invoker.getUrl()); 154 }
155if (onthrowMethod != null && !onthrowMethod.isAccessible()) {
156 onthrowMethod.setAccessible(true);
157 }
158 Class<?>[] rParaTypes = onthrowMethod.getParameterTypes();
159if (rParaTypes[0].isAssignableFrom(exception.getClass())) {
160try {
161 Object[] args = invocation.getArguments();
162 Object[] params;
163
164if (rParaTypes.length > 1) {
165// onthrow(xx, Object[]) 两个参数:第⼀个参数接收exception,第⼆个接收所有的真实请求参数
166if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
167 params = new Object[2];
168 params[0] = exception;
169 params[1] = args;
170// onthrow(xx, Object... args) 多个参数:第⼀个参数接收exception,后边⼏个接收所有的真实请求参数
171 } else {
172 params = new Object[args.length + 1];
173 params[0] = exception;
174 System.arraycopy(args, 0, params, 1, args.length);
175 }
176 } else {
177// onthrow(xx) 只有⼀个参数:接收exception
178 params = new Object[]{exception};
179 }
180 onthrowMethod.invoke(onthrowInst, params);
181 } catch (Throwable e) {
182 logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), e);
183 }
184 } else {
185 logger.error(invocation.getMethodName() + ".call back method invoke error . callback method :" + onthrowMethod + ", url:" + invoker.getUrl(), exception);
186 }
187 }
188 }
从@Activate(group = Constants.CONSUMER)来看FutureFilter只⽤在consumer端;不管是同步调⽤还是异步调⽤,都会⾛FutureFilter。

原理:
⾸先⾛oninvoke(String name)⽅法;
然后⾛sayHello(String name)
最后根据同步还是异步分别⾛不同的逻辑。

其中同步很简单,看sayHello(String name)的返回结果RpcResult中是否有exception对象,如果有,执⾏onthrow(Throwable ex, String name);如果没有执⾏onreturnWithoutParam(String result)。

异步的操作:由于不知道provider什么时候回执⾏完毕,所以要添加回调等待provider端返回结果后,再执⾏onthrow(Throwable ex, String name)或者
onreturnWithoutParam(String result),这种模式很重要,这是统计异步⽅法调⽤时间的⼀种⾮常好的模式。

重点看⼀下异步!
三、异步回调模式
1private void asyncCallback(final Invoker<?> invoker, final Invocation invocation) {
2 Future<?> f = RpcContext.getContext().getFuture();
3if (f instanceof FutureAdapter) {
4 ResponseFuture future = ((FutureAdapter<?>) f).getFuture();
5// 3.1 调⽤服务之后:设置回调ResponseCallback对象到DefaultFuture中,当provider返回响应时,执⾏DefaultFuture.doReceived⽅法,该⽅法会调⽤ResponseCallback对象的done或者caught⽅法
6 future.setCallback(new ResponseCallback() {
7public void done(Object rpcResult) {
8if (rpcResult == null) {
9 logger.error(new IllegalStateException("invalid result value : null, expected " + Result.class.getName()));
10return;
11 }
12///must be rpcResult
13if (!(rpcResult instanceof Result)) {
14 logger.error(new IllegalStateException("invalid result type :" + rpcResult.getClass() + ", expected " + Result.class.getName()));
15return;
16 }
17 Result result = (Result) rpcResult;
18if (result.hasException()) {
19 fireThrowCallback(invoker, invocation, result.getException());
20 } else {
21 fireReturnCallback(invoker, invocation, result.getValue());
22 }
23 }
24
25public void caught(Throwable exception) {
26 fireThrowCallback(invoker, invocation, exception);
27 }
28 });
29 }
30 }
上述的future对象是DefaultFuture,这⾥⾸先new了⼀个ResponseCallback回调函数,设置到了DefaultFuture的ResponseCallback callback属性中。

来看⼀下DefaultFuture类:
1private volatile Response response;
2private volatile ResponseCallback callback;
3
4public boolean isDone() {
5return response != null;
6 }
7
8public void setCallback(ResponseCallback callback) {
9if (isDone()) {
10 invokeCallback(callback);
11 } else {
12boolean isdone = false;
13 lock.lock();
14try {
15if (!isDone()) {
16this.callback = callback;
17 } else {
18 isdone = true;
19 }
20 } finally {
21 lock.unlock();
22 }
23if (isdone) {
24 invokeCallback(callback);
25 }
26 }
27 }
1private void invokeCallback(ResponseCallback c) {
2 ResponseCallback callbackCopy = c;
3if (callbackCopy == null) {
4throw new NullPointerException("callback cannot be null.");
5 }
6 c = null;
7 Response res = response;
8if (res == null) {
9throw new IllegalStateException("response cannot be null. url:" + channel.getUrl());
10 }
11
12if (res.getStatus() == Response.OK) {
13try {
14// 返回正常,回调ResponseCallback回调函数的done⽅法
15 callbackCopy.done(res.getResult());
16 } catch (Exception e) {
17 logger.error("callback invoke error .reasult:" + res.getResult() + ",url:" + channel.getUrl(), e);
18 }
19 } else if (res.getStatus() == Response.CLIENT_TIMEOUT || res.getStatus() == Response.SERVER_TIMEOUT) {
20try {
21 TimeoutException te = new TimeoutException(res.getStatus() == Response.SERVER_TIMEOUT, channel, res.getErrorMessage());
22// 如果超时,回调ResponseCallback回调函数的caught⽅法
23 callbackCopy.caught(te);
24 } catch (Exception e) {
25 logger.error("callback invoke error ,url:" + channel.getUrl(), e);
26 }
27 } else {
28try {
29 RuntimeException re = new RuntimeException(res.getErrorMessage());
30// 其他异常,回调ResponseCallback回调函数的caught⽅法
31 callbackCopy.caught(re);
32 } catch (Exception e) {
33 logger.error("callback invoke error ,url:" + channel.getUrl(), e);
34 }
35 }
36 }
从setCallback(ResponseCallback callback),如果此时provider端已经返回了响应(response!=null),则直接执⾏ResponseCallback回调函数中的done⽅法或者caught⽅法;否则,将上边创建的ResponseCallback实例赋值给DefaultFuture的ResponseCallback callback属性中。

那么之后会在什么时候执⾏回调函数的⽅法呢?当consumer接收到provider的响应的时候!
1public static void received(Channel channel, Response response) {
2try {
3 DefaultFuture future = FUTURES.remove(response.getId());
4if (future != null) {
5 future.doReceived(response);
6 } else {
7 logger.warn("The timeout response finally returned at "
8 + (new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS").format(new Date()))
9 + ", response " + response
10 + (channel == null ? "" : ", channel: " + channel.getLocalAddress()
11 + " -> " + channel.getRemoteAddress()));
12 }
13 } finally {
14 CHANNELS.remove(response.getId());
15 }
16 }
17
18private void doReceived(Response res) {
19 lock.lock();
20try {
21 response = res;
22if (done != null) {
23 done.signal();
24 }
25 } finally {
26 lock.unlock();
27 }
28// 调⽤回调函数
29if (callback != null) {
30 invokeCallback(callback);
31 }
32 }
当provider返回响应时,会调⽤DefaultFuture.received(Channel channel, Response response)⽅法(),此时会执⾏回调函数。

事件通知的源码就分析完了!最后看⼀个回调模式的使⽤场景:统计异步⽅法的调⽤时间。

1private void asyncCallback(final Invoker<?> invoker, final Invocation invocation) {
2 Future<?> f = RpcContext.getContext().getFuture();
3final long start = System.currentTimeMillis();
4if (f instanceof FutureAdapter) {
5 ResponseFuture future = ((FutureAdapter<?>) f).getFuture();
6 future.setCallback(new ResponseCallback() {
7public void done(Object rpcResult) {
8 long cost = System.currentTimeMillis() - start;
9 }
10 });
11 }
12 }
上边的代码只是⼀个形式,实际上start时间需要在调⽤sayHello⽅法之前进⾏记录。

相关文档
最新文档