SpringBoot 整合 Dubbo 案例

大纲

前言

Dubbo 是阿里巴巴开源的产品,采用二进制通信,相比 OpenFeign 的 HTTP 通信,具有性能优势,而且可以轻松集成到 SpringBoot 和 Spring Cloud 中使用,对于性能要求比较高的场景,使用比较广泛。

学习资源

版本对应关系

SpringBoot 与 Dubbo 的版本必须互相匹配,否则不同版本之间可能会存在兼容性问题,最终导致服务无法正常运行。两者的版本对应关系如下:

Dubbo 分支最新版本 JDKSpringBoot 详细说明
3.3.x3.3.08, 17, 212.x、3.x 生产可用(推荐,长期维护)! 最新 Triple 协议升级,内置 Metrics、Tracing、GraalVM 支持等
3.2.x3.2.108, 172.x、3.x 生产可用(长期维护)!
3.1.x3.1.118, 172.x、3.x 仅修复安全漏洞!
3.0.x3.0.1582.x 停止维护!
2.7.x2.7.2382.x 停止维护!
2.6.x2.6.206, 7- 停止维护!
2.5.x2.5.106, 7- 停止维护!

如果仍然使用版本低于 2.7.0 的旧版 Dubbo,请使用以下 Spring Boot 启动器:

Dubbo Spring BootDubboSpring Boot
0.2.1.RELEASE2.6.5+2.x
0.1.2.RELEASE2.6.5+1.x

SpringBoot 整合 Dubbo

版本说明

组件版本说明
SpringBoot2.7.18
Dubbo Spring Boot Starter2.7.23 依赖 Dubbo 2.7.23
Zookeeper Server3.8.4ZooKeeper 服务器,作为服务注册中心
Curator Recipes5.5.0 用于 Dubbo 连接 ZooKeeper 注册中心,依赖 Curator Client 5.5.0 和 ZooKeeper Client 3.7.1
JDK11 支持 JDK 1.8 及以上版本

提示

  • 如果使用的是高版本的 SpringBoot(比如 3.3.3),那么需要使用 3.3.1 版本的 Dubbo Spring Boot Starter。
  • 如果使用的是较低版本的 ZooKeeper 服务器(比如 3.4.10),那么就需要降低 Curator Recipes 的版本,否则 Dubbo 将无法正常连接 ZooKeeper 服务器。

模块说明

  • api:抽取出来的公共模块,存放公用的实体类和接口
  • provider:服务提供者,实现 api 模块中的接口
  • customer:服务消费者,调用服务提供者中的接口

案例代码

API 模块

  • 为了简化代码,API 模块只简单定义一个接口
1
2
3
4
5
public interface DemoService {

String sayHello(String name);

}

Provider 模块

  • 引入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<properties>
<spring-boot.version>2.7.18</spring-boot.version>
<dubbo-springboot.version>2.7.23</dubbo-springboot.version>
<curator.version>5.5.0</curator.version>
</properties>

<dependencyManagement>
<dependencies>
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.clay.dubbo</groupId>
<artifactId>dubbo-lesson-04-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-springboot.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
  • 接口实现类,@DubboService 注解主要用于暴露服务,使其能够被 Dubbo 框架识别并注册到服务注册中心。
1
2
3
4
5
6
7
8
9
10
11
import org.apache.dubbo.config.annotation.DubboService;

@DubboService
public class DemoServiceImpl implements DemoService {

@Override
public String sayHello(String name) {
return "Hello " + name;
}

}
  • 主启动类
1
2
3
4
5
6
7
8
@SpringBootApplication
public class ProviderApplication {

public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class);
}

}
  • 配置文件(application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server:
port: 9090

spring:
application:
name: dubbo-provider-application

dubbo:
# 服务信息
application:
name: ${spring.application.name}
# 注册中心地址
registry:
address: zookeeper://127.0.0.1:2181
# 服务提供者的协议
protocol:
name: dubbo
port: 20880
# 扫描 Dubbo 相关的注解
scan:
base-packages: com.clay.dubbo.provider

提示

若不希望在 YML 配置文件中指定 dubbo.scan.base-packages 参数,那么可以在主启动类上标注 @EnableDubbo(scanBasePackages = "xxx") 注解或者 @DubboComponentScan(basePackages = "xxx") 注解来替代。

Consumer 模块

  • 引入依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<properties>
<spring-boot.version>2.7.18</spring-boot.version>
<dubbo-springboot.version>2.7.23</dubbo-springboot.version>
<curator.version>5.5.0</curator.version>
</properties>

<dependencyManagement>
<dependencies>
<!-- SpringBoot -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>

<dependencies>
<dependency>
<groupId>com.clay.dubbo</groupId>
<artifactId>dubbo-lesson-04-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-springboot.version}</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
  • 业务测试类,@DubboReference 注解主要用于在服务消费者端引用远程服务提供者的服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.apache.dubbo.config.annotation.DubboReference;

@Slf4j
@RestController
public class DemoController {

/**
* 引用远程服务
* <p> 可以指定版本、负载均衡算法、重试次数、超时毫秒等。
* <p> 负载均衡默认为 random,还可以配置为:roundrobin 、leastactive 、consistenthash
* <p> 重试次数 retries 可以统一在 application.yml 进行配置,对于增删改等非幂等操作,建议不要重试
* <p> 超时毫秒数 timeout 可以统一在 application.yml 进行配置,也可以在具体服务上做个性化配置
*/
@DubboReference(loadbalance = "random")
private DemoService demoService;

@GetMapping("/sayHello/{name}")
public String sayHello(@PathVariable("name") String name) {
String result = demoService.sayHello(name);
log.info("===> " + result);
return result;
}

}
  • 主启动类
1
2
3
4
5
6
7
8
@SpringBootApplication
public class ConsumerApplication {

public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class);
}

}
  • 配置文件(application.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
server:
port: 9091

spring:
application:
name: dubbo-consumer-application

dubbo:
# 服务信息
application:
name: ${spring.application.name}
# 注册中心地址
registry:
address: zookeeper://127.0.0.1:2181
# 扫描 Dubbo 相关的注解
scan:
base-packages: com.clay.dubbo.consumer
# 消费行为配置
consumer:
# 关闭了启动检查,这样消费者启动时,不会到注册中心里面检查服务提供者是否存在
check: false
# 建议统一配置为不重试请求,对于查询等幂等操作来说可以在代码中单独配置重试次数
retries: 0
# 默认情况下限制请求必须在 1000 毫秒内完成,对于具体服务可以在代码中单独配置
timeout: 1000

提示

若不希望在 YML 配置文件中指定 dubbo.scan.base-packages 参数,那么可以在主启动类上标注 @EnableDubbo(scanBasePackages = "xxx") 注解或者 @DubboComponentScan(basePackages = "xxx") 注解来替代。

测试代码

使用 Postman 等工具访问 http://localhost:9091/sayHello/dubbo 接口,若接口可以返回 Hello dubbo 结果,则说明 SpringBoot 整合 Dubbo 成功。

下载代码

  • 完整的案例代码可以直接从 GitHub 下载对应章节 dubbo-lesson-04

使用 Nacos 注册中心

早期的 Dubbo 都采用 Zookeeper 作为注册中心,现在基本上都使用 Nacos 作为注册中心,毕竟 Dubbo 和 Nacos 都是阿里巴巴的产品。若希望在 SpringBoot 整合 Dubbo 时,使用 Nacos 作为注册中心,那么在上述案例的基础上,按照以下步骤进行操作即可。

  • (1) 由于不再需要使用 ZooKeeper 作为注册中心,因此需要移除 curator-recipes 依赖
1
2
3
4
5
6
7
<!-->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>${curator.version}</version>
</dependency>
-->
  • (2) 由于需要使用 Nacos 作为注册中心,因此需要引入 dubbo-registry-nacos
1
2
3
4
5
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>2.7.23</version>
</dependency>
  • (3) 在 Provider 和 Consumer 模块中,指定 Nacos 注册中心的地址
1
2
3
4
dubbo:
# 注册中心地址
registry:
address: nacos://127.0.0.1:8848

参考资料