1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

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

前言

原本今天是想分享dubbo的事件通知机制的,但是试了好多次,一直都没有成功,最后看到官方给出的回复:

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

也就是说事件通知在注解模式下不支持,所以我就不打算继续研究了,我现在就只想研究注解模式,感兴趣的小伙伴自己去看下,这里我们就简单介绍下事件通知机制。

事件通知

事件通知机制简单来说就是针对在调用之前、调用之后、出现异常时的时间通知,就是我们人为指定的回调函数,从2.0.7以后的版本开始支持,我想后续应该会增加对注解模式的支持。

事件回调机制主要是针对服务调用方,也就是消费者的,配置方式也很简单,只需要在dubbo的消费者xml中加入dubbo:method,并指定oninvokeonreturnonthrow方法:

<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是我们自己定义的回调接口,具体实现如下:

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)
    }
}

我的错误

下面是我的调用方代码:

@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;
    }

回调接口实现:

@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);
    }
}

我通过注解指定了oninvoke的方法,但是在调用服务提供者的时候报错了,控制台错误提示如下:

然后我debug发现,是因为AsyncMethodInfooninvokeMethod方法为空导致的

在搜集错误的过程中,我发现了下面这些很有用的知识点,各位小伙伴可以看下:

oninvoke方法
  • 必须具有与真实的被调用方法sayHello相同的入参列表:例如,oninvoke(String name)
onreturn方法
  • 至少要有一个入参且第一个入参必须与getUserName的返回类型相同,接收返回结果:例如,onReturnWithoutParam(String result)
  • 可以有多个参数,多个参数的情况下,第一个后边的所有参数都是用来接收getUserName入参的:例如, onreturn(String result, String name)
onthrow方法
  • 至少要有一个入参且第一个入参类型为Throwable或其子类,接收返回结果;例如,onthrow(Throwable ex);

  • 可以有多个参数,多个参数的情况下,第一个后边的所有参数都是用来接收getUserName入参的:例如,onthrow(Throwable ex, String name);

  • 如果是consumer在调用provider的过程中,出现异常时不会走onthrow方法的,onthrow方法只会在provider返回的RpcResult中含有Exception对象时,才会执行。(dubbo中下层服务的Exception会被放在响应RpcResultexception对象中传递给上层服务)

好吧,我妥协了

最后,我还是用xml的方式测试了,确实是可以回调的,dubbo消费者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);
    }

}

然后启动运行,从控制台看出,我们的回调方法都被执行了:

根据实现机制,我推测回调方法是基于动态代理实现的,关于动态代理的应用我们前面在分享手写rpc的时候有讲过,最常用的场景之一就是AOP,据说SpringStruts等框架就是通过动态代理技术来实现日志、切面编程这些操作的。

柳暗花明又一村

xml的方式测试完成后,我又看了下关于那个问题官方给出的回复,发现在2021.5.12日这个问题已经被修复了,说明之后的版本已经可以通过注解方式进行事件通知回调了,而且我亲测在2.7.12之后的版本就已经可以了:

感觉我可真是个小机灵鬼,这都让我发现了😊,当然我也停享受这个柳暗花明又一村的感觉的,这种学习方式感觉挺好,就像发现新大陆一样……

总结

目前来看,事件通知的最大应用场景就是AOP,但是缺点是,每个方法都需要单独指定(@Method(name = "sayHello", oninvoke = "callBackDemoService.oninvoke")中的name是必填项,而且不支持正则表达式),这就很不友好了,但是有总比没有强,你说呢?

好了,今天的内容就到这里吧,有兴趣的小伙伴自己动手试下哦!

项目源码地址如下:

https://github.com/Syske/learning-dome-code/tree/dev/spring-boot-dubbo-demo
posted @ 2021-08-17 16:47  云中志  阅读(68)  评论(0编辑  收藏  举报