<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          柳暗花明又一村——dubbo事件通知踩坑

          共 7845字,需瀏覽 16分鐘

           ·

          2021-08-19 06:59

          前言

          原本今天是想分享dubbo的事件通知機(jī)制的,但是試了好多次,一直都沒(méi)有成功,最后看到官方給出的回復(fù):

          oninvoke ,onreturn,onthrow do work well in xml ,but do not work when use annotation

          也就是說(shuō)事件通知在注解模式下不支持,所以我就不打算繼續(xù)研究了,我現(xiàn)在就只想研究注解模式,感興趣的小伙伴自己去看下,這里我們就簡(jiǎn)單介紹下事件通知機(jī)制。

          事件通知

          事件通知機(jī)制簡(jiǎn)單來(lái)說(shuō)就是針對(duì)在調(diào)用之前、調(diào)用之后、出現(xiàn)異常時(shí)的時(shí)間通知,就是我們?nèi)藶橹付ǖ幕卣{(diào)函數(shù),從2.0.7以后的版本開(kāi)始支持,我想后續(xù)應(yīng)該會(huì)增加對(duì)注解模式的支持。

          事件回調(diào)機(jī)制主要是針對(duì)服務(wù)調(diào)用方,也就是消費(fèi)者的,配置方式也很簡(jiǎn)單,只需要在dubbo的消費(fèi)者xml中加入dubbo:method,并指定oninvoke、onreturnonthrow方法:

          <bean id ="demoCallback" class = "org.apache.dubbo.callback.implicit.NotifyImpl" />
          <dubbo:reference id="demoService" interface="org.apache.dubbo.callback.implicit.IDemoService" version="1.0.0" group="cn" >
                <dubbo:method name="get" async="true" onreturn = "demoCallback.onreturn" onthrow="demoCallback.onthrow" oninvoke = "demoCallback.oninvoke"/>
          </dubbo:reference>

          其中,demoCallback是我們自己定義的回調(diào)接口,具體實(shí)現(xiàn)如下:

          class NotifyImpl implements Notify {
              public Map<Integer, Person>    ret    = new HashMap<Integer, Person>();
              public Map<Integer, Throwable> errors = new HashMap<Integer, Throwable>();
              
              public void onreturn(Person msg, Integer id) {
                  System.out.println("onreturn:" + msg);
                  ret.put(id, msg);
              }
              
              public void onthrow(Throwable ex, Integer id) {
                  errors.put(id, ex);
              }
              
              public void oninvoke(Integer id) {
                  System.out.print(id)
              }
          }

          我的錯(cuò)誤

          下面是我的調(diào)用方代碼:

          @DubboReference(version = "1.0", interfaceName = "demoService", interfaceClass = DemoService.class,
                      loadbalance 
          "roundrobin", methods = {@Method(name = "sayHello", oninvoke = "callBackDemoService.oninvoke")})
              private DemoService demoService;

              @RequestMapping("/test")
              public Object demo() {
                  String hello = demoService.sayHello("world");
                  System.out.println(hello);
                  return hello;
              }

          回調(diào)接口實(shí)現(xiàn):

          @Service("callBackDemoService")
          public class CallBackDemoServiceImpl implements CallBackDemoSevice {
              @Override
              public void oninvoke(String name) {
                  System.out.println("oninvoke name =" + name);
              }

              @Override
              public String onreturn(String response) {
                  System.out.println("onreturn response =" + response);
                  return "onreturn" + response;
              }

              @Override
              public void onthrow(Throwable t) {
                  System.err.println("onthrow Throwable =" + t);
              }
          }

          我通過(guò)注解指定了oninvoke的方法,但是在調(diào)用服務(wù)提供者的時(shí)候報(bào)錯(cuò)了,控制臺(tái)錯(cuò)誤提示如下:

          然后我debug發(fā)現(xiàn),是因?yàn)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">AsyncMethodInfo的oninvokeMethod方法為空導(dǎo)致的

          在搜集錯(cuò)誤的過(guò)程中,我發(fā)現(xiàn)了下面這些很有用的知識(shí)點(diǎn),各位小伙伴可以看下:

          oninvoke方法
          • 必須具有與真實(shí)的被調(diào)用方法sayHello相同的入?yún)⒘斜恚豪纾?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">oninvoke(String name)
          onreturn方法
          • 至少要有一個(gè)入?yún)⑶业谝粋€(gè)入?yún)⒈仨毰cgetUserName的返回類(lèi)型相同,接收返回結(jié)果:例如,onReturnWithoutParam(String result)
          • 可以有多個(gè)參數(shù),多個(gè)參數(shù)的情況下,第一個(gè)后邊的所有參數(shù)都是用來(lái)接收getUserName入?yún)⒌模豪纾?onreturn(String result, String name)
          onthrow方法
          • 至少要有一個(gè)入?yún)⑶业谝粋€(gè)入?yún)㈩?lèi)型為Throwable或其子類(lèi),接收返回結(jié)果;例如,onthrow(Throwable ex);

          • 可以有多個(gè)參數(shù),多個(gè)參數(shù)的情況下,第一個(gè)后邊的所有參數(shù)都是用來(lái)接收getUserName入?yún)⒌模豪纾?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(255, 100, 65);">onthrow(Throwable ex, String name);

          • 如果是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)RpcResultexception對(duì)象中傳遞給上層服務(wù))

          好吧,我妥協(xié)了

          最后,我還是用xml的方式測(cè)試了,確實(shí)是可以回調(diào)的,dubbo消費(fèi)者xml配置如下:

          <?xml version="1.0" encoding="utf-8" ?>
          <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
                 xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
                 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                 http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
          >

              <context:property-placeholder/>
              <bean id ="demoCallback" class = "io.github.syske.demo.service.consumer.callback.impl.CallBackDemoServiceImpl" />
              <dubbo:reference id="demoService" interface="io.github.syske.common.facade.DemoService" version="1.0" >
                  <dubbo:method name="sayHello" async="true" oninvoke="demoCallback.oninvoke" onreturn = "demoCallback.onreturn" onthrow="demoCallback.onthrow" />
              </dubbo:reference>

              <dubbo:application name="callback-consumer"/>

              <dubbo:registry address="zookeeper://${zookeeper.address:127.0.0.1}:2181"/>

          </beans>

          修改主程序,刪除原有注解:

          @SpringBootApplication
          //@EnableDubbo
          public class DemoConsumerApplication {

              public static void main(String[] args) {
                  ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("consumer.xml");
                  context.start();
                  DemoService demoService = (DemoService) context.getBean("demoService");
                  String hello = demoService.sayHello("world");
                  System.out.println(hello);
              }

          }

          然后啟動(dòng)運(yùn)行,從控制臺(tái)看出,我們的回調(diào)方法都被執(zhí)行了:

          根據(jù)實(shí)現(xiàn)機(jī)制,我推測(cè)回調(diào)方法是基于動(dòng)態(tài)代理實(shí)現(xiàn)的,關(guān)于動(dòng)態(tài)代理的應(yīng)用我們前面在分享手寫(xiě)rpc的時(shí)候有講過(guò),最常用的場(chǎng)景之一就是AOP,據(jù)說(shuō)Spring、Struts等框架就是通過(guò)動(dòng)態(tài)代理技術(shù)來(lái)實(shí)現(xiàn)日志、切面編程這些操作的。

          柳暗花明又一村

          xml的方式測(cè)試完成后,我又看了下關(guān)于那個(gè)問(wèn)題官方給出的回復(fù),發(fā)現(xiàn)在2021.5.12日這個(gè)問(wèn)題已經(jīng)被修復(fù)了,說(shuō)明之后的版本已經(jīng)可以通過(guò)注解方式進(jìn)行事件通知回調(diào)了,而且我親測(cè)在2.7.12之后的版本就已經(jīng)可以了:

          感覺(jué)我可真是個(gè)小機(jī)靈鬼,這都讓我發(fā)現(xiàn)了??,當(dāng)然我也停享受這個(gè)柳暗花明又一村的感覺(jué)的,這種學(xué)習(xí)方式感覺(jué)挺好,就像發(fā)現(xiàn)新大陸一樣……

          總結(jié)

          目前來(lái)看,事件通知的最大應(yīng)用場(chǎng)景就是AOP,但是缺點(diǎn)是,每個(gè)方法都需要單獨(dú)指定(@Method(name = "sayHello", oninvoke = "callBackDemoService.oninvoke")中的name是必填項(xiàng),而且不支持正則表達(dá)式),這就很不友好了,但是有總比沒(méi)有強(qiáng),你說(shuō)呢?

          好了,今天的內(nèi)容就到這里吧,有興趣的小伙伴自己動(dòng)手試下哦!

          項(xiàng)目源碼地址如下:

          https://github.com/Syske/learning-dome-code/tree/dev/spring-boot-dubbo-demo
          - END -


          瀏覽 69
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产豆花在线视频 | 人人操黄色片段 | 天天操天天日天天干男 | 日本日日操 | 亚洲人妖在线 |