dubbo新手學(xué)習(xí)之事件通知實(shí)踐教程
前言
今天主要給大家分享一下dubbo的事件通知機(jī)制。
先看下dubbo中文官網(wǎng)的示例解釋:事件通知。
在調(diào)用之前、調(diào)用之后、出現(xiàn)異常時(shí),會(huì)觸發(fā) oninvoke、onreturn、onthrow 三個(gè)事件,可以配置當(dāng)事件發(fā)生時(shí),通知哪個(gè)類的哪個(gè)方法.
實(shí)踐
溪源目的是快速學(xué)習(xí)dubbo的相關(guān)機(jī)制,故定義的相同的接口和方法,采用分包的方式解耦合,便于后期維護(hù)。
先看服務(wù)接口
dubbo-demo-interface
目錄如圖
**
UserNotifyService **
/**
* @author wx
* @date 2020/9/8 1:44 下午
* 測(cè)試事件通知
*/
public interface UserNotifyService {
/**
* 獲取用戶名字
* @param userId
* @return
*/
String getUserName(String userId);
}
dubbo-demo-xml-provider
目錄如下
notify-provider.xml
定義一個(gè)新的配置文件,用于配置事件通知相關(guān)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
擴(kuò)展點(diǎn)
1. oninvoke方法:
必須具有與真實(shí)的被調(diào)用方法sayHello相同的入?yún)⒘斜恚豪纾琽ninvoke(String name)
2. onreturn方法:
2.1 至少要有一個(gè)入?yún)⑶业谝粋€(gè)入?yún)⒈仨毰cgetUserName的返回類型相同,接收返回結(jié)果:例如,onReturnWithoutParam(String result);
2.2 可以有多個(gè)參數(shù),多個(gè)參數(shù)的情況下,第一個(gè)后邊的所有參數(shù)都是用來(lái)接收getUserName入?yún)⒌模豪纾?onreturn(String result, String name)
3. onthrow方法:
3.1 至少要有一個(gè)入?yún)⑶业谝粋€(gè)入?yún)㈩愋蜑門hrowable或其子類,接收返回結(jié)果;例如,onthrow(Throwable ex);
3.2 可以有多個(gè)參數(shù),多個(gè)參數(shù)的情況下,第一個(gè)后邊的所有參數(shù)都是用來(lái)接收getUserName入?yún)⒌模豪?,onthrow(Throwable ex, String name);
4. 如果是consumer在調(diào)用provider的過(guò)程中,出現(xiàn)異常時(shí)不會(huì)走onthrow方法的,onthrow方法只會(huì)在provider返回的RpcResult中含有Exception對(duì)象時(shí),才會(huì)執(zhí)行。(dubbo中下層服務(wù)的Exception會(huì)被放在響應(yīng)RpcResult的exception對(duì)象中傳遞給上層服務(wù))
對(duì)于上面的解釋,大家可能會(huì)存在疑惑,部分方法要求第一個(gè)參數(shù)為服務(wù)接口的返回值類型???約定大于配置???揭開(kāi)迷底的方法就是debug源碼設(shè)計(jì)實(shí)現(xiàn)邏輯~
源代碼:
/**
* @author wx
* @date 2020/9/8 1:53 下午
*/
public interface ConsumerNotifyService {
/**
* 調(diào)用之前
* @param name
*/
void onInvoke(String name);
/**
* 無(wú)參數(shù):調(diào)用之后
* @param result 參數(shù)用于接收 [事件通知]服務(wù)接口的方法返回值類型保持一致
*/
void onReturnWithoutParam(String result);
/**
* 有參數(shù):調(diào)用之后
* @param result 第一個(gè)參數(shù) 接收 [事件通知]服務(wù)接口的方法返回值類型保持一致
* @param name 第二個(gè)或者之后,與[事件通知]服務(wù)接口的方法入?yún)⒈3忠恢?
*/
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("[事件通知]執(zhí)行onInvoke方法,參數(shù):" + name);
}
@Override
public void onReturnWithoutParam(String result) {
System.out.println("[事件通知]執(zhí)行onReturnWithoutParam方法,返回結(jié)果:" + result);
}
@Override
public void onReturn(String result, String name) {
System.out.println("[事件通知]執(zhí)行onReturn方法,參數(shù):" + name + ", 返回結(jié)果:" + result);
}
@Override
public void onThrow(Throwable ex, String name) {
System.out.println("[事件通知]執(zhí)行onThrow方法,參數(shù):" + name + ", 異常信息:" + ex.getMessage());
}
}
notify-consumer.xml
同理,消費(fèi)者端也新建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);
}
運(yùn)行
分別啟動(dòng)生產(chǎn)者和消費(fèi)者,運(yùn)行結(jié)果如圖:
分別執(zhí)行了onInvoke方法和onReturn方法

源碼
關(guān)于dubbo的事件通知機(jī)制,源碼實(shí)現(xiàn)基本上位于FutureFilter類中,先給大家貼一下類方法目錄:

上面溪源提到為什么部分方法要約定第一個(gè)參數(shù)與接口方法返回值類型保持一致呢?下面揭開(kāi)迷底,我們進(jìn)入fireReturnCallback方法
private void fireReturnCallback(final Invoker<?> invoker, final Invocation invocation, final Object result) {
....//省略部分代碼
Object[] params;
//獲取方法參數(shù)類型
Class<?>[] rParaTypes = onReturnMethod.getParameterTypes();
if (rParaTypes.length > 1) {
//兩個(gè)參數(shù):第一個(gè)參數(shù)與真實(shí)方法getUserName方法返回結(jié)果類型相同,第二個(gè)接收所有的真實(shí)請(qǐng)求參數(shù)
if (rParaTypes.length == 2 && rParaTypes[1].isAssignableFrom(Object[].class)) {
params = new Object[2];
// 真實(shí)方法的返回結(jié)果
params[0] = result;
//執(zhí)行方法入?yún)?
params[1] = args;
} else {
//多個(gè)參數(shù):第一個(gè)參數(shù)與真實(shí)方法getUserName結(jié)果類型相同,后邊幾個(gè)接收所有的真實(shí)請(qǐng)求參數(shù)
params = new Object[args.length + 1];
params[0] = result;
System.arraycopy(args, 0, params, 1, args.length);
}
} else {
//只有一個(gè)參數(shù):接收返回執(zhí)行結(jié)果
params = new Object[]{result};
}
try {
onReturnMethod.invoke(onReturnInst, params);
} catch (InvocationTargetException e) {
fireThrowCallback(invoker, invocation, e.getTargetException());
} catch (Throwable e) {
fireThrowCallback(invoker, invocation, e);
}
}
事件通知機(jī)制,底層實(shí)際上利用了反射機(jī)制實(shí)現(xiàn)類方法的調(diào)用。
溪源初次接觸dubbo本地存根機(jī)制,如文中存在錯(cuò)誤之處,希望大家及時(shí)指正!
源碼傳送門:https://github.com/stream-source/dubbo/tree/master/dubbo-demo
總結(jié)
到此這篇關(guān)于dubbo新手學(xué)習(xí)之事件通知實(shí)踐教程的文章就介紹到這了,更多相關(guān)dubbo事件通知內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
基于strict-origin-when-cross-origin問(wèn)題的解決
這篇文章主要介紹了基于strict-origin-when-cross-origin問(wèn)題的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03
Java 生成隨機(jī)單據(jù)號(hào)的實(shí)現(xiàn)示例
本文主要介紹了Java 生成隨機(jī)單據(jù)號(hào)的實(shí)現(xiàn)示例,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2023-09-09
Java操作excel的三種常見(jiàn)方法實(shí)例
這篇文章主要給大家介紹了關(guān)于Java操作excel的三種常見(jiàn)方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2021-04-04
spring schedule實(shí)現(xiàn)動(dòng)態(tài)配置執(zhí)行時(shí)間
這篇文章主要介紹了spring schedule實(shí)現(xiàn)動(dòng)態(tài)配置執(zhí)行時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-11-11
Mybatis pagehelper分頁(yè)插件使用過(guò)程解析
這篇文章主要介紹了mybatis pagehelper分頁(yè)插件使用過(guò)程解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02
maven如何打包動(dòng)態(tài)環(huán)境變量(包括啟動(dòng)腳本)
這篇文章主要介紹了maven如何打包動(dòng)態(tài)環(huán)境變量(包括啟動(dòng)腳本)問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04
劍指Offer之Java算法習(xí)題精講數(shù)組與字符串
跟著思路走,之后從簡(jiǎn)單題入手,反復(fù)去看,做過(guò)之后可能會(huì)忘記,之后再做一次,記不住就反復(fù)做,反復(fù)尋求思路和規(guī)律,慢慢積累就會(huì)發(fā)現(xiàn)質(zhì)的變化2022-03-03

