SpringCloud+nacos整合dubbo实现同步/异步调用

前言:为啥要整合dubbo呢,可以在微服务间异步调用咯

dubbo为啥能异步呢?它集成了Jdk8中的CompletableFuture,有关CompletableFuture介绍参见其官方文档https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/CompletableFuture.html

有关CompletableFuture用法可以参见这篇文章https://zhuanlan.zhihu.com/p/344431341

一、整体架构

 二、添加dubbo依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-dubbo</artifactId>
        </dependency>

三、配置application.yml

Service-B:device

server:
  port: 9085
spring:
  application:
    name: @project.artifactId@  #项目名字作为服务名
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.30.100:8848  #nacos服务的地址
  main:
    #springboot2.1,允许覆盖bean
    allow-bean-definition-overriding: true

dubbo:
  scan:
    #本服务拥有@Service的那个包,将自己的服务暴露出去
    basePackages: com.manager.device.service
  protocol:
    #Windows平台使用虚拟网卡或装过虚拟机做此配置,一般为以太网ip而不是VMnet
    host: 192.168.30.26
    name: dubbo
    port: -1  #-1 表示端口自动增加,避免占用,默认从 20880 开始
  registry:
   #将dubbo地址挂载到nacos地址,也可为spring-cloud://192.168.30.100:8848 address: nacos://192.168.30.100:8848 cloud: #服务提供者的服务名,*表示订阅所有服务 subscribed-services: '*' consumer: check: false #启动时是否检查依赖的服务-相互调用不做此配置启动不了

Service-A:account

server:
  port: 9080
spring:
  application:
    name: @project.artifactId@
  cloud:
    nacos:
      discovery:
        server-addr: 192.168.30.100:8848
  main:
    allow-bean-definition-overriding: true

dubbo:
  scan:
   basePackages: com.manager.account.service protocol: host:
192.168.30.26 name: dubbo port: -1 registry: address: nacos://192.168.30.100:8848 cloud: subscribed-services: '*' consumer: check: false #启动时是否检查依赖的服务

四、公共api接口

创建新module(mypublic-api),编写如下接口

Service-A:account

public interface UserClient {
     String fun2();
}

Service-B:device

public interface DeviceClient {
     String fun3();
}

五、Service实现

导入公共API

        <dependency>
            <groupId>com.mypublic.cloud</groupId>
            <artifactId>mypublic-api</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>

Service-A:account服务实现

import org.apache.dubbo.config.annotation.Service;

@Service
public class UserService implements UserClient {
    @Override
    public String fun2() {
        return "这里是用户服务端!";
    }
}

Service-B:device服务实现

import org.apache.dubbo.config.annotation.Service;

@Service
public class DeviceService implements DeviceClient {

    @Override
    public String fun3() {
        return "这里是设备服务端!";
    }
}

六、controller层实现

Service-A:account 远程调用 Service-B:device

import org.apache.dubbo.config.annotation.Reference;

@RestController
public class UserController  {

    @Reference
    private DeviceClient deviceClient;

    @RequestMapping("/a")
    public String fun2(){
        String s = deviceClient.fun3();
        System.out.println(Thread.currentThread().getName()+"用户端调用设备端结果:"+s);
        return s;
    }
}

Service-B:device 远程调用 Service-A:account

import org.apache.dubbo.config.annotation.Reference;

@RestController
public class DeviceController {

    @Reference
    private UserClient userClient;

    @RequestMapping("/b1")
    public String fun3(){
        String s = userClient.fun2();
        System.out.println(Thread.currentThread().getName()+"设备端调用用户端结果:"+s); 

     return s;
  } 
}

七、启动类

Service-A:account 

@SpringBootApplication
@EnableDiscoveryClient
public class AccountApplication {
    public static void main(String[] args) {
        SpringApplication.run(AccountApplication.class,args);
    }
}

Service-B:device

@SpringBootApplication
@EnableDiscoveryClient
public class DeviceApplication {
    public static void main(String[] args) {
        SpringApplication.run(DeviceApplication.class,args);
    }
}

八、测试结果:

Service-A:account 

Service-B:device

 可以看到相互调用可以实现了!

 九、异步调用

在@Service和@Reference添加异步属性async = true

@Service(async = true)
@Reference(async = true)

然后重启项目调用上面Controller接口

 会发现,调用是成功了,但是没有返回结果,想要返回结果咋办呢?使用CompletableFuture解决

去掉@Service和@Reference异步属性async = true

方法1.使用dubbo自带的org.apache.dubbo.rpc.RpcContext;获取CompletableFuture,不用@Reference或者@Autowired进行注入,但比较繁琐,建议用方法2

@RequestMapping("/a")
    public String fun4(){
        ReferenceConfig<DeviceClient> referenceConfig = new ReferenceConfig<DeviceClient>();

        //设置为异步
        referenceConfig.setAsync(true);
     //要调用的公共接口的名字.class(DeviceClient.class) referenceConfig.setInterface(DeviceClient.
class); DeviceClient greetingService = referenceConfig.get(); //调用,返回为null greetingService.fun3(); //异步执行回调函数获取返回的结果 CompletableFuture<String> future = RpcContext.getContext().getCompletableFuture(); future.whenComplete((v, t) -> { if (null != t) { t.printStackTrace();//异常 } else { System.out.println(v);//得到返回值v } }); return "ok"; }

方法2.使用java自带的java.util.concurrent.CompletableFuture中的CompletableFuture,和dubbo没啥关系,可以不用dubbo用其他方法比如Feign实现异步调用。

@RequestMapping("/a1")
    public List<String> fun3(){
        CompletableFuture<String> future = CompletableFuture.supplyAsync(()->{
            //调用Service-B中的fun3
            return deviceClient.fun3();
        });

        //用于返回
        List<String> list=new ArrayList<>();

        //设置监听结果,非阻塞
        future.whenComplete((v,e)->{
            if (e!= null) {
                e.printStackTrace();
            }else {
                list.add(v);//放进去返回给前端
                System.out.println(Thread.currentThread().getName()+"用户客户端调用设备端结果:"+v);
            }
        });

        return list;
    }

测试结果:

 

 PS:个人不喜欢用dubbo,后期我会用Feign结合CompletableFuture实现微服务间的异步调用,感觉比用dubbo好用还方便。

 

posted @ 2022-05-06 10:47  蒂雪凌星  阅读(702)  评论(0)    收藏  举报
Live2D