Dubbo官网:https://cn.dubbo.apache.org/zh-cn/
Dubbo 是一款高性能、轻量级的开源Java RPC框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,服务自动注册和发现。分布式系统是将一个系统拆分为多个不同的服务。
Spring Cloud | dubbo | |
---|---|---|
框架模型 | 是基于HTTP协议的RESTful风格调用 | 采用RPC远程过程调用形式 |
服务发现与治理 | 支持注册中心 | 支持注册中心 |
服务调用 | 基于HTTP/Rest的短连接 | 长连接 |
配置管理 | 支持灵活的配置管理和动态刷新 | 需要手动编写接口或启用第三方集成 |
节点 | 角色说明 |
---|---|
Provider | 暴露服务的服务提供方 |
Consumer | 调用远程服务的服务消费方 |
Registry | 服务注册与发现的注册中心 |
Monitor | 统计服务的调用次数和调用时间的监控中心 |
Container | 服务运行容器 |
功能上有很多类似的地方,因为都是专注于远程调用这个动作。比如注册中心、负载均衡、失败重试熔断、链路监控。
实现上:Dubbo除了注册中心,其它的都自己实现了,而Feign大部分功能都是依赖全家桶的组件来实现的。Dubbo小而专一,专注于远程调用。而Spring全家桶而言,远程调用只是一个重要的功能而已。
在本任务中,将分为 3 个子模块进行独立开发,模拟生产环境下的部署架构。
interface // 共享 API 模块
consumer // 消费端模块
provider // 服务端模块
如上所示,共有 3 个模块,其中 interface 模块被 consumer 和 provider 两个模块共同依赖,存储 RPC 通信使用的 API 接口。
对于一个微服务化的应用来说,注册中心是不可或缺的一个组件。只有通过注册中心,消费端才可以成功发现服务端的地址信息,进而进行调用。(用Nacos作为注册中心即可)
基于 IntelliJ IDEA 进行工程的搭建以及测试。
搭建了基础项目之后,我们还需要创建 interface 、provider 和 consumer 三个子模块。
在搭建完项目的基础框架以后,我们需要先添加 Dubbo 和注册中心Nacos的相关的 maven 依赖。对于多模块项目,首先需要在父项目的 pom.xml 里面配置依赖信息。
编辑 ./pom.xml 这个文件,添加下列配置。
<properties>
<dubbo.version>3.2.0-beta.4dubbo.version>
<java.version>1.8java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<spring-boot.version>2.6.13spring-boot.version>
properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-dependenciesartifactId>
<version>${spring-boot.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-bomartifactId>
<version>${dubbo.version}version>
<type>pomtype>
<scope>importscope>
dependency>
<dependency>
<groupId>com.alibaba.nacosgroupId>
<artifactId>nacos-clientartifactId>
<version>2.1.0version>
dependency>
dependencies>
dependencyManagement>
然后在 consumer 和 provider 两个模块 pom.xml 中进行具体依赖的配置。
<dependencies>
<dependency>
<groupId>com.examplegroupId>
<artifactId>interfaceartifactId>
<version>0.0.1-SNAPSHOTversion>
dependency>
<dependency>
<groupId>org.apache.dubbogroupId>
<artifactId>dubbo-spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starterartifactId>
dependency>
<dependency>
<groupId>com.alibaba.nacosgroupId>
<artifactId>nacos-clientartifactId>
<version>2.1.0version>
dependency>
dependencies>
服务接口 Dubbo 中沟通消费端和服务端的桥梁。
在此目录下定义DemoServie接口:
public interface DemoService {
String sayHello(String name);
}
在 DemoService 中,定义了 sayHello 这个方法。后续服务端发布的服务,消费端订阅的服务都是围绕着 DemoService 接口展开的。
定义了服务接口之后,可以在服务端这一侧定义对应的实现,这部分的实现相对于消费端来说是远端的实现,本地没有相关的信息。
@DubboService
public class DemoServiceImpl implements DemoService {
@Override
public String sayHello(String name) {
return "Hello " + name;
}
}
在 DemoServiceImpl 中,实现了 DemoService 接口,对于 sayHello 方法返回 Hello name。
注:在DemoServiceImpl 类中添加了 @DubboService 注解,通过这个配置可以基于 Spring Boot 去发布 Dubbo 服务。
通过 Spring Boot 的方式配置 Dubbo 的一些基础信息。
首先,我们先创建服务端的配置文件。
在 provider 模块的 resources 资源文件夹下建立 application.yml 文件,定义如下:
dubbo:
application:
name: dubbo-springboot-demo-provider
protocol:
name: dubbo
port: -1
registry:
# 使用的注册中心地址
address: nacos://localhost:8848
在这个配置文件中,定义了 Dubbo 的应用名、Dubbo 协议信息、Dubbo 使用的注册中心地址。
除了配置 Yaml 配置文件之外,我们还需要创建基于 Spring Boot 的启动类。
首先,我们先创建服务端的启动类。
@SpringBootApplication
@EnableDubbo
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
在这个启动类中,配置了一个 ProviderApplication 去读取我们前面第 6 步中定义的 application.yml 配置文件并启动应用。@EnableDubbo做了两件事,一个是初始化Dubbo核心组件,加载Dubbo配置到内存。另一个是注册BeanPostProcessor,用来扫描@Service和@Reference注解。
我们在 Spring Boot 模式下还可以基于 CommandLineRunner去创建。
CommandLineRunner是个接口,有一个run()方法。为了使用CommandLineRunner我们需要创建一个类实现该接口并覆盖run()方法。使用@Component注解实现类。当SpringApplication.run()启动spring boot程序时,启动完成之前,CommandLineRunner.run()会被执行。CommandLineRunner的run()方法接收启动服务时传过来的参数。
@Component
public class Task implements CommandLineRunner {
@DubboReference
private DemoService demoService;
@Override
public void run(String... args) throws Exception {
String result = demoService.sayHello("world");
System.out.println("Receive result ======> " + result);
new Thread(()-> {
while (true) {
try {
Thread.sleep(1000);
System.out.println(new Date() + " Receive result ======> " + demoService.sayHello("world"));
} catch (InterruptedException e) {
e.printStackTrace();
Thread.currentThread().interrupt();
}
}
}).start();
}
}
在 Task 类中,通过@DubboReference 从 Dubbo 获取了一个 RPC 订阅,这个 demoService 可以像本地调用一样直接调用。在 run方法中创建了一个线程进行调用。
dubbo:
application:
name: dubbo-springboot-demo-consumer
protocol:
name: dubbo
port: -1
registry:
address: nacos://localhost:8848
@SpringBootApplication
@EnableDubbo
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class,args);
}
}
代码就已经开发完成了,本小节将启动整个项目并进行验证。
首先是启动provider.Application ,等待一会出现如下图所示的日志(Current Spring Boot Application is await)即代表服务提供者启动完毕,标志着该服务提供者可以对外提供服务了。
然后启动ConsumerApplication,等待一会出现如下图所示的日志(Hello world )即代表服务消费端启动完毕并调用到服务端成功获取结果。
使用Dubbo可以将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用灵活扩展,使前端应用能更快速的响应多变的市场需求。