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好用还方便。

浙公网安备 33010602011771号