>>分享孙卫琴的Java技术专稿和著作 书籍支持  卫琴直播  品书摘要  在线测试  资源下载  联系我们
发表一个新主题 开启一个新投票 回复文章 您是本文章第 8349 个阅读者 刷新本主题
 * 贴子主题:  【Spring Cloud Alibaba专题】Dubbo框架中提供者回调消费者 回复文章 点赞(0)  收藏  
作者:sunweiqin    发表时间:2022-08-25 09:27:51     消息  查看  搜索  好友  邮件  复制  引用

本文参考孙卫琴,杜聚宾所创作的<<Spring Cloud Alibaba微服务开发宝典>>一书,即将出版

在Dubbo框架中,消费者可以远程调用提供者的服务方法。此外,提供者也可以调用消费者的方法,这种调用过程称为回调。
在图1中,有两个消费者访问提供者。消费者远程调用提供者的HelloServiceImpl对象的sayHello()方法,该方法在提供者方执行;此外,提供者会回调消费者的MyCallbackListener对象的report()方法,该方法在消费者方执行。

点击在新窗口中浏览原图
CTRL+鼠标滚轮放大或缩小
图1  提供者回调消费者的方法

提供者微服务回调消费者微服务的创建步骤如下。
(1)在一个公共模块中创建CallbackListener回调接口,参见例程1。

/* 例程1  CallbackListener.java */
public interface CallbackListener {
  //这是提供者回调消费者的方法
  public void report(String msg);
}

(2)在公共模块的HelloService接口中加入两个方法:

//提供者的服务方法
public String sayHello(String username,String key);

//消费者通过此方法向提供者注册CallbackListener
public void addListener(String key,
                             CallbackListener listener);

为了便于提供者管理和访问特定CallbackListener对象,每个CallbackListener对象都有唯一的key。

(3)在消费者模块中创建MyCallbackListener类,它实现了CallbackListener接口,参见例程2。

/* 例程2  MyCallbackListener.java */
public class MyCallbackListener implements CallbackListener{
  @Override
  public void report(String msg) {
    System.out.println(msg);
  }
}

(4)在消费者模块的HelloConsumerController类中,增加init()和testCallback()方法:

@Value("${server.port}")
private String servicePort;

//该注解表示Spring框架创建了控制器对象后就会调用init()方法
@PostConstruct  
public void init(){
  //向提供者注册MyCallbackListener对象,以servicePort作为key
  helloService.addListener(servicePort,
                                new MyCallbackListener());
}

@GetMapping(value = "/callback/{username}")
public String testCallback(@PathVariable String username){
  //调用提供者的sayHello()服务方法
  return helloService.sayHello(username,servicePort);
}

以上代码把当前微服务实例监听的servicePort作为MyCallbackListener对象的key。在实际应用中,也可以用其他具有业务含义的属性作为key,只要保证每个MyCallbackListener对象的key具有唯一性即可。
(5)修改提供者模块的HelloServiceImpl类,实现HelloService接口的addListener()方法和sayHello(String username,String key)方法,参见例程3。

/* 例程3  HelloServiceImpl.java */
@DubboService(
  //指明addListener()方法的listener参数是回调类型的参数
  methods={
    @Method(name="addListener",
             arguments={@Argument(index=1,callback=true)})}
)
public class HelloServiceImpl implements HelloService {
  //存放消费者所注册的CallbackListener对象
  private final Map<String, CallbackListener> listeners =
      new ConcurrentHashMap<String, CallbackListener>();

  public HelloServiceImpl() {
    //创建定时向消费者推送当前时间信息的线程
    Thread t = new Thread(new Runnable() {
      public void run() {
        while(true){
          try{
            for(Map.Entry<String, CallbackListener> entry :
                                          listeners.entrySet()){
              try{
                //回调消费者的CallbackListener的report()方法
                entry.getValue().report("当前时间:"
                                             +new Date());
              }catch (Throwable t) {
                listeners.remove(entry.getKey());
              }
            }

            Thread.sleep(5000);//通过睡眠定时向消费者推送时间信息
          }catch (Throwable ex){
             ex.printStackTrace();
          }
        }
      }
    });

    t.setDaemon(true);   //作为后台线程运行
    t.start();
  }

  @Override
  public void addListener(String key,
                              CallbackListener listener) {
    //加入消费者注册的CallbackListener对象
    listeners.put(key, listener);  
  }

  @Override
  public String sayHello(String username,String key){
    CallbackListener listener=listeners.get(key);

    //回调消费者的CallbackListener对象的report()方法
    listener.report(username+"打过招呼。");

    return "Hello," + username;
  }
  ……
}

HelloServiceImpl类的@DubboService注解嵌套了@Method注解,@Method注解又嵌套了@Argument(index=1,callback = true)注解。@Argument注解的作用是指明addListener()方法的索引为1的参数(即listener参数)是回调类型的参数。
(6)先后启动提供者模块和消费者模块。当提供者模块的HelloConsumerController控制器在初始化的过程中,会调用helloService.addListener(servicePort, new MyCallbackListener())方法,向提供者注册MyCallbackListener对象。

在提供者方,HelloServiceImpl对象在创建时启动了一个后台线程,该线程定时回调消费者注册的所有CallbackListener对象的report()方法,推送当前的时间信息。

通过浏览器访问http://localhost:8082/callback/Tom,提供者方的HelloServiceImpl对象的sayHello(String username,String key)方法会回调当前消费者注册的CallbackListener对象的report()方法,然后返回响应结果。在IDEA中,在消费者模块的控制台,会打印如下信息:

当前时间:Fri May 27 13:25:38 CST 2022
当前时间:Fri May 27 13:25:43 CST 2022
当前时间:Fri May 27 13:25:49 CST 2022
Tom打过招呼。
当前时间:Fri May 27 13:25:54 CST 2022
当前时间:Fri May 27 13:25:59 CST 2022

  Java面向对象编程-->图形用户界面(下)
  JavaWeb开发-->访问数据库(Ⅰ)
  JSP与Hibernate开发-->JPA API的高级用法
  Java网络编程-->用Spring整合CXF发布Web服务
  精通Spring-->组合(Composition)API
  Vue3开发-->Vue简介
  【Vue.js技术专题】注册全局组件和局部组件
  【Vue.js技术专题】路由管理器的基本用法
  【Vue.js技术专题】CSS中DOM元素的过渡模式
  【Vue.js技术专题】插槽slot的基本用法
  【Vue.js技术专题】在Vue项目中使用Axios
  【Vue.js技术专题】Vuex中异步操作
  【Java基础编程专题】使用和创建JavaDoc文档
  【持久化专题】为什么JPA和Hibernate的持久化方法都抛出运行...
  【Spring专题】用AOP和SLF4J输出日志的范例
  【持久化专题】JPA API的级联操作
  【持久化专题】用orphanRemoval属性映射父子关系
  【持久化专题】对象-关系的映射概念
  【Java编程基础专题】用Scanner类读取用户在控制台输入的数据
  【Java网络编程专题】用Apache HttpClients下载网上的图片等...
  【持久化专题】比较JPA的EntityManager接口与Hibernate的Ses...
  更多...
 IPIP: 已设置保密
树形列表:   
1页 0条记录 当前第1
发表一个新主题 开启一个新投票 回复文章


中文版权所有: JavaThinker技术网站 Copyright 2016-2026 沪ICP备16029593号-2
荟萃Java程序员智慧的结晶,分享交流Java前沿技术。  联系我们
如有技术文章涉及侵权,请与本站管理员联系。