整合流程

1.启动zookeeper注册中心

这里我是在自己的云服务器上使用docker部署的,运行docker run -d -p 2181:2181 zookeeper即可。

2.构建项目

项目结构如下图,api模块用于暴露公共的Service接口,provider模块为服务提供者,consumer模块为服务调用者。

image-20250224175214038

3.代码编写

3.1.api模块

api模块只需定义一个UserService接口即可,结构如下图:

image-20250224175538222

UserService.java代码如下:

1
2
3
4
5
package com.penciy.service;

public interface UserService {
String hello(String name);
}

pom.xml如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.penciy</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>

<properties>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

</project>
3.2.服务提供者provider

服务提供者负责实现 api模块中定义的服务接口,并将这些服务注册到 ZooKeeper 注册中心。整体结构如下图:

image-20250224175859449

pom.xml如下:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.penciy</groupId>
<artifactId>provider</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>provider</name>
<description>provider</description>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

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

<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>

<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>

<dependency>
<groupId>com.penciy</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<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>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.penciy.provider.ProviderApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>

</project>

UserServiceImpl.java代码如下,使用 Dubbo 注解 @DubboService将实现的服务注册到 ZooKeeper 注册中心,以便服务消费者可以发现和调用这些服务。:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.penciy.provider.service;

import com.penciy.service.UserService;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.stereotype.Component;

@DubboService
@Component
public class UserServiceImpl implements UserService {

@Override
public String hello(String name) {
return "hello dubbo, I am " + name;
}
}

启动类ProviderApplication.java代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.penciy.provider;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo
@SpringBootApplication
public class ProviderApplication {

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

}

application.properties如下(这里隐去了我的服务器ip):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
server.port=8081
# 指定 Dubbo 服务的注册中心地址,这里使用 ZooKeeper 作为注册中心
# 服务提供者会将自身服务信息注册到该 ZooKeeper 实例,服务消费者也会从这里获取服务信息
dubbo.registry.address=zookeeper://xx.xxx.xxx.xxx:2181
# 设置 Dubbo 服务在注册中心的注册模式为 instance,即服务以实例为单位进行注册
# 每个服务实例会在注册中心单独注册自身元数据,方便服务消费者精准选择
dubbo.registry.register-mode=instance
# 定义 Dubbo 应用的名称,用于在注册中心和日志等场景中标识当前服务提供者应用
dubbo.application.name=demo-provider
# 指定 Dubbo 服务之间通信使用的协议为 dubbo 协议,这是 Dubbo 框架默认的高性能远程调用协议
dubbo.protocol.name=dubbo
# 指定 Dubbo 服务暴露的端口号,服务提供者会在该端口监听服务消费者的请求
# 服务消费者通过该端口与服务提供者建立连接以调用服务
dubbo.protocol.port=20880
# 指定 Dubbo 扫描服务实现类的基础包路径
# Dubbo 会在该包及其子包下查找带有 @DubboService 注解的服务实现类,并将其注册到注册中心
dubbo.scan.base-packages=com.penciy.provider.service
3.3.服务消费者consumer

consumer模块是服务的消费者,它依赖api模块中的服务接口,从 ZooKeeper 注册中心获取服务提供者的信息,并调用这些服务。整体结构如下:

image-20250224185628082

pom.xml如下:

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.penciy</groupId>
<artifactId>consumer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>consumer</name>
<description>consumer</description>
<properties>
<java.version>17</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

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

<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>

<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-zookeeper-curator5-spring-boot-starter</artifactId>
<version>3.3.0</version>
</dependency>

<dependency>
<groupId>com.penciy</groupId>
<artifactId>api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<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>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>17</source>
<target>17</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.penciy.consumer.ConsumerApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

HelloController.java代码如下,这里的userService是通过@DubboReference注解进行注入的,实际运行时会使用一个动态代理调用注册中心中的远程服务:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.penciy.consumer.controller;

import com.penciy.service.UserService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/hello")
public class HelloController {

@DubboReference
UserService userService;

@GetMapping("/dubbo")
public String hello(String name) {
return userService.hello(name);
}
}

启动类ConsumerApplication如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.penciy.consumer;

import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@EnableDubbo
@SpringBootApplication
public class ConsumerApplication {

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

}

application.properties如下:

1
2
3
4
5
6
7
8
9
10
11
server.port=8082
# 指定 Dubbo 服务的注册中心地址,使用 ZooKeeper 作为注册中心
dubbo.registry.address=zookeeper://xx.xxx.xxx.xxx:2181
# 设置 Dubbo 服务在注册中心的注册模式为 instance,以服务实例为单位进行注册
dubbo.registry.register-mode=instance
# 定义 Dubbo 应用的名称,用于在注册中心和日志等场景中标识当前服务消费者应用
dubbo.application.name=demo-consumer
# 指定 Dubbo 服务之间通信使用的协议为 dubbo 协议,这是 Dubbo 框架默认的高性能远程调用协议
dubbo.protocol.name=dubbo
# 指定 Dubbo 应用的 QoS(服务质量)服务所监听的端口,可通过此端口执行管理和监控命令
dubbo.application.qos-port=33333

4.功能测试

分别启动provider和consumer,访问localhost:8082/hello/dubbo/?name=penciy,发现服务消费者可以成功调用提供者的接口实现类:

image-20250224190649658

5.总结

dubbo的入门使用十分简单,只需要引入依赖并配置,然后在服务调用者和服务提供者的启动类上加入@EnableDubbo注解,在服务提供者提供的远程服务实现上加入@DubboService,在服务调用者需要注入的远程服务上加入@DubboReference注解即可。

6.踩坑记录

**问题:**服务消费者始终无法发现注册中心的服务

使用 Zookeeper 作为注册中心实现自动服务发现 | Apache Dubbo中有一句话:

  • Dubbo 3.3.0 版本开始正式支持 JDK 17,如果您使用 JDK 17,则必须选用 dubbo-dependencies-zookeeper-curator5 或 dubbo-zookeeper-curator5-spring-boot-starter 依赖,对应的 Zookeeper Server 推荐是 3.8.0 版本及以上。

一开始使用的是3.5.x的zookeeper,猜测可能是版本原因,用docker重新安装了高版本的zookeeper后问题解决。

__END__