目錄
- 實踐
- dubbo-demo-interface
- dubbo-demo-xml-provider
- notify-provider.xml
- UserNotifyServiceImpl
- ProviderApplication
- dubbo-demo-xml-consumer
- ConsumerNotifyService
- ConsumerNotifyServiceImpl
- notify-consumer.xml
- ConsumerApplication
- 運行
- 原始碼
今天主要給大家分享一下dubbo的事件通知機制,
先看下dubbo中文官網的示例解釋:事件通知,
在呼叫之前、呼叫之后、出現例外時,會觸發 oninvoke、onreturn、onthrow 三個事件,可以配置當事件發生時,通知哪個類的哪個方法.
實踐
溪源目的是快速學習dubbo的相關機制,故定義的相同的介面和方法,采用分包的方式解耦合,便于后期維護,
先看服務介面
dubbo-demo-interface
- 目錄如圖

- ** UserNotifyService **
/**
* @author wx
* @date 2020/9/8 1:44 下午
* 測驗事件通知
*/
public interface UserNotifyService {
/**
* 獲取用戶名字
* @param userId
* @return
*/
String getUserName(String userId);
}
dubbo-demo-xml-provider
- 目錄如下

notify-provider.xml
定義一個新的組態檔,用于配置事件通知相關bean,

UserNotifyServiceImpl
/**
* @author wx
* @date 2020/9/8 1:46 下午
*/
@Service
public class UserNotifyServiceImpl implements UserNotifyService {
private static final String USER_ID = "1503892";
@Override
public String getUserName(String userId) {
if (StringUtils.isBlank(userId)) {
throw new RpcException("userId is null");
}
return USER_ID.equals(userId) ? "溪~源" : "";
}
}
ProviderApplication
/**
* 事件通知
* @throws IOException
*/
private static void notifyTest() throws IOException {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/notify-provider.xml");
context.start();
System.in.read();
}
dubbo-demo-xml-consumer
- 目錄如下

ConsumerNotifyService
擴展點
1. oninvoke方法:
必須具有與真實的被呼叫方法sayHello相同的入參串列:例如,oninvoke(String name)
2. onreturn方法:
2.1 至少要有一個入參且第一個入參必須與getUserName的回傳型別相同,接識訓傳結果:例如,onReturnWithoutParam(String result);
2.2 可以有多個引數,多個引數的情況下,第一個后邊的所有引數都是用來接收getUserName入參的:例如, onreturn(String result, String name)
3. onthrow方法:
3.1 至少要有一個入參且第一個入參型別為Throwable或其子類,接識訓傳結果;例如,onthrow(Throwable ex);
3.2 可以有多個引數,多個引數的情況下,第一個后邊的所有引數都是用來接收getUserName入參的:例如,onthrow(Throwable ex, String name);
4. 如果是consumer在呼叫provider的程序中,出現例外時不會走onthrow方法的,onthrow方法只會在provider回傳的RpcResult中含有Exception物件時,才會執行,(dubbo中下層服務的Exception會被放在回應RpcResult的exception物件中傳遞給上層服務)
對于上面的解釋,大家可能會存在疑惑,部分方法要求第一個引數為服務介面的回傳值型別???約定大于配置???揭開迷底的方法就是debug原始碼設計實作邏輯~
源代碼:
/**
* @author wx
* @date 2020/9/8 1:53 下午
*/
public interface ConsumerNotifyService {
/**
* 呼叫之前
* @param name
*/
void onInvoke(String name);
/**
* 無引數:呼叫之后
* @param result 引數用于接收 [事件通知]服務介面的方法回傳值型別保持一致
*/
void onReturnWithoutParam(String result);
/**
* 有引數:呼叫之后
* @param result 第一個引數 接收 [事件通知]服務介面的方法回傳值型別保持一致
* @param name 第二個或者之后,與[事件通知]服務介面的方法入參保持一致
*/
void onReturn(String result, String name);
/**
* 拋例外
* @param ex
* @param name
*/
void onThrow(Throwable ex, String name);
}
ConsumerNotifyServiceImpl
/**
* @author wx
* @date 2020/9/8 1:59 下午
*/
@Service
public class ConsumerNotifyServiceImpl implements ConsumerNotifyService{
@Override
public void onInvoke(String name) {
System.out.println("[事件通知]執行onInvoke方法,引數:" + name);
}
@Override
public void onReturnWithoutParam(String result) {
System.out.println("[事件通知]執行onReturnWithoutParam方法,回傳結果:" + result);
}
@Override
public void onReturn(String result, String name) {
System.out.println("[事件通知]執行onReturn方法,引數:" + name + ", 回傳結果:" + result);
}
@Override
public void onThrow(Throwable ex, String name) {
System.out.println("[事件通知]執行onThrow方法,引數:" + name + ", 例外資訊:" + ex.getMessage());
}
}
notify-consumer.xml
同理,消費者端也新建notify-consumer.xml檔案,具體配置如圖:

ConsumerApplication
private static void notifyTest() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring/notify-consumer.xml");
UserNotifyService notifyService = context.getBean(UserNotifyService.class);
String userName = notifyService.getUserName("1503892");
System.out.println(userName);
}
運行
分別啟動生產者和消費者,運行結果如圖:
分別執行了onInvoke方法和onReturn方法

原始碼
關于dubbo的事件通知機制,原始碼實作基本上位于FutureFilter類中,先給大家貼一下類方法目錄:

上面溪源提到為什么部分方法要約定第一個引數與介面方法回傳值型別保持一致呢?下面揭開迷底,我們進入fireReturnCallback方法
private void fireReturnCallback(final Invoker<?> invoker, final Invocation invocation, final Object result) {
....//省略部分代碼
Object[] params;
//獲取方法引數型別
Class<?>[] rParaTypes = onReturnMethod.getParameterTypes();
if (rParaTypes.length > 1) {
//兩個引數:第一個引數與真實方法getUserName方法回傳結果型別相同,第二個接收所有的真實請求引數
if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
params = new Object[2];
// 真實方法的回傳結果
params[0] = result;
//執行方法入參
params[1] = args;
} else {
//多個引數:第一個引數與真實方法getUserName結果型別相同,后邊幾個接收所有的真實請求引數
params = new Object[args.length + 1];
params[0] = result;
System.arraycopy(args, 0, params, 1, args.length);
}
} else {
//只有一個引數:接識訓傳執行結果
params = new Object[]{result};
}
try {
onReturnMethod.invoke(onReturnInst, params);
} catch (InvocationTargetException e) {
fireThrowCallback(invoker, invocation, e.getTargetException());
} catch (Throwable e) {
fireThrowCallback(invoker, invocation, e);
}
}
事件通知機制,底層實際上利用了反射機制實作類方法的呼叫,
溪源初次接觸dubbo本地存根機制,如文中存在錯誤之處,希望大家及時指正!
原始碼傳送門:https://github.com/stream-source/dubbo/tree/master/dubbo-demo
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/11735.html
標籤:其他
上一篇:dos命令中如何匹配日期
