dubbo实践最小治理单元demo

这个示例将使用Spring Boot 3 + Dubbo 3.3,采用Nacos 作为注册中心,完整演示服务定义、暴露和调用。


1. 整体目录结构

dubbo-demo(父工程) ├── pom.xml(父POM,管理版本) ├── common(公共模块) │ ├── pom.xml │ └── src/main/java/com/demo/common/ │ ├── dto/User.java │ └── api/UserService.java // 纯业务接口,无任何注解 ├── service-b(服务提供方,端口8081) │ ├── pom.xml │ ├── src/main/java/com/demo/serviceb/ │ │ ├── ServiceBApplication.java │ │ └── service/ │ │ └── UserServiceImpl.java // 实现 common 中的接口 │ └── src/main/resources/application.yml └── service-a(服务调用方,端口8080) ├── pom.xml ├── src/main/java/com/demo/servicea/ │ ├── ServiceAApplication.java │ └── controller/OrderController.java // 注入 Dubbo 远程服务 └── src/main/resources/application.yml

2. 父工程 pom.xml(根目录)

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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.demo</groupId><artifactId>dubbo-demo</artifactId><version>1.0.0</version><packaging>pom</packaging><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.2.8</version><relativePath/></parent><properties><java.version>17</java.version><dubbo.version>3.3.0</dubbo.version></properties><dependencyManagement><dependencies><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-bom</artifactId><version>${dubbo.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><modules><module>common</module><module>service-b</module><module>service-a</module></modules></project>

3. common 模块(定义 API 契约)

common/pom.xml

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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"><parent><artifactId>dubbo-demo</artifactId><groupId>com.demo</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>common</artifactId><dependencies><!-- 仅需最基础的依赖,不需要 Dubbo 注解 --><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><!-- 为了兼容 DTO 序列化 --><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-annotations</artifactId></dependency></dependencies></project>

common/src/main/java/com/demo/common/dto/User.java

packagecom.demo.common.dto;importlombok.Data;importjava.io.Serializable;@DatapublicclassUserimplementsSerializable{privatestaticfinallongserialVersionUID=1L;privateLongid;privateStringname;privateStringemail;}

common/src/main/java/com/demo/common/api/UserService.java

packagecom.demo.common.api;importcom.demo.common.dto.User;// 注意:这是一个纯 Java 接口,没有任何注解!// 在 Dubbo 中,接口就是契约,不需要 @FeignClient 这类东西publicinterfaceUserService{UsergetUserById(Longid);}

4. service-b 模块(服务提供方)

service-b/pom.xml

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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"><parent><artifactId>dubbo-demo</artifactId><groupId>com.demo</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>service-b</artifactId><dependencies><!-- 依赖 common 模块 --><dependency><groupId>com.demo</groupId><artifactId>common</artifactId><version>1.0.0</version></dependency><!-- Spring Boot Web(提供 HTTP 能力,可选) --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Dubbo Spring Boot Starter(核心) --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId></dependency><!-- Nacos 注册中心 --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-nacos-spring-boot-starter</artifactId></dependency></dependencies></project>

service-b/src/main/resources/application.yml

server:port:8081spring:application:name:service-bdubbo:application:name:service-b# 应用名,与 spring.application.name 一致protocol:name:tri# Triple 协议(Dubbo 3.x 推荐)port:50051# Dubbo 服务端口registry:address:nacos://127.0.0.1:8848# 注册中心地址# 如果使用 Zookeeper,改为: zookeeper://127.0.0.1:2181scan:base-packages:com.demo.serviceb.service# 扫描 @DubboService 注解

service-b/src/main/java/com/demo/serviceb/ServiceBApplication.java

packagecom.demo.serviceb;importorg.apache.dubbo.config.spring.context.annotation.EnableDubbo;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication@EnableDubbo// 开启 Dubbo 支持(等价于 @EnableDubboConfig + @DubboComponentScan)publicclassServiceBApplication{publicstaticvoidmain(String[]args){SpringApplication.run(ServiceBApplication.class,args);}}

service-b/src/main/java/com/demo/serviceb/service/UserServiceImpl.java

packagecom.demo.serviceb.service;importcom.demo.common.api.UserService;importcom.demo.common.dto.User;importorg.apache.dubbo.config.annotation.DubboService;importorg.springframework.stereotype.Component;@Component@DubboService// 暴露服务到注册中心publicclassUserServiceImplimplementsUserService{@OverridepublicUsergetUserById(Longid){Useruser=newUser();user.setId(id);user.setName("张三(来自Dubbo服务)");user.setEmail("zhangsan@dubbo.com");returnuser;}}

5. service-a 模块(服务调用方)

service-a/pom.xml

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="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"><parent><artifactId>dubbo-demo</artifactId><groupId>com.demo</groupId><version>1.0.0</version></parent><modelVersion>4.0.0</modelVersion><artifactId>service-a</artifactId><dependencies><!-- 依赖 common 模块 --><dependency><groupId>com.demo</groupId><artifactId>common</artifactId><version>1.0.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- Dubbo Spring Boot Starter --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-spring-boot-starter</artifactId></dependency><!-- Nacos 注册中心 --><dependency><groupId>org.apache.dubbo</groupId><artifactId>dubbo-nacos-spring-boot-starter</artifactId></dependency></dependencies></project>

service-a/src/main/resources/application.yml

server:port:8080spring:application:name:service-adubbo:application:name:service-aregistry:address:nacos://127.0.0.1:8848# 注册中心地址consumer:check:false# 启动时不检查提供者是否在线(开发环境推荐)timeout:3000# 调用超时时间(毫秒)

service-a/src/main/java/com/demo/servicea/ServiceAApplication.java

packagecom.demo.servicea;importorg.apache.dubbo.config.spring.context.annotation.EnableDubbo;importorg.springframework.boot.SpringApplication;importorg.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication@EnableDubbopublicclassServiceAApplication{publicstaticvoidmain(String[]args){SpringApplication.run(ServiceAApplication.class,args);}}

service-a/src/main/java/com/demo/servicea/controller/OrderController.java

packagecom.demo.servicea.controller;importcom.demo.common.api.UserService;importcom.demo.common.dto.User;importorg.apache.dubbo.config.annotation.DubboReference;importorg.springframework.web.bind.annotation.GetMapping;importorg.springframework.web.bind.annotation.PathVariable;importorg.springframework.web.bind.annotation.RestController;@RestControllerpublicclassOrderController{@DubboReference// 引用远程 Dubbo 服务privateUserServiceuserService;@GetMapping("/order/{id}/user")publicUsergetOrderUser(@PathVariable("id")Longid){// 像调用本地方法一样调用远程服务returnuserService.getUserById(id);}}

6. 启动前准备:启动 Nacos 注册中心

在运行服务之前,你需要启动 Nacos:

# 下载 Nacos 并解压,然后启动(这里以 2.3.0 版本为例)# Mac/Linuxshstartup.sh-mstandalone# Windowsstartup.cmd-mstandalone

如果使用 Zookeeper,则需要启动 Zookeeper 服务,并将配置中的nacos改为zookeeper


7. 运行测试

  1. 先启动 service-b,观察控制台输出,会看到 Dubbo 服务成功注册到 Nacos。
  2. 再启动 service-a,观察控制台输出。
  3. 访问http://localhost:8080/order/123/user,返回:
{"id":123,"name":"张三(来自Dubbo服务)","email":"zhangsan@dubbo.com"}

8. 与 Feign 版本的关键对比

对比点Feign (OpenFeign)Dubbo
common 模块内容@FeignClient+@GetMapping注解接口纯 Java 接口+ DTO,无任何注解
提供方(B)暴露方式实现 Controller,用@RestController实现 Service,用@DubboService
调用方(A)注入方式@Autowired注入@DubboReference注入
通信协议HTTP(默认)Triple(基于 HTTP/2,默认)
注册中心自动集成 Spring Cloud 注册中心通过dubbo.registry配置
接口变更影响修改@GetMapping路径,A 服务编译期报错修改接口方法名/参数,A 服务编译期报错
启动类注解@EnableFeignClients@EnableDubbo

9. 注意事项(避坑指南)

问题解决方案
端口冲突Dubbo 的dubbo.protocol.portRPC 端口,与server.port(HTTP端口)不同,可独立设置。
服务找不到检查注册中心地址是否正确,且 B 服务已启动。consumer.check=false可避免启动时因服务未上线而报错。
接口包路径不一致A 和 B 的common包路径必须完全一致(如都是com.demo.common.api),否则 Dubbo 无法匹配。
DTO 序列化所有 DTO 必须实现Serializable,并建议显式声明serialVersionUID
Spring Boot 版本Dubbo 3.3.x 支持 Spring Boot 3.x;如果使用 Spring Boot 2.x,需引入dubbo-spring-boot-starter3.0.x 版本。

总结:标准微服务的 Dubbo 最小单元

┌──────────────────────────────────────────────────────────┐ │ common 模块 (纯 Java 接口 + DTO) │ │ └── UserService.java (无任何注解) │ │ └── User.java (实现 Serializable) │ └──────────────────────────────────────────────────────────┘ ▲ 依赖 ▲ 依赖 │ │ ┌──────────┴──────────┐ ┌─────────────┴────────────┐ │ service-b (提供方) │ │ service-a (调用方) │ │ @EnableDubbo │ │ @EnableDubbo │ │ @DubboService │ │ @DubboReference │ │ 实现 UserService │──RPC─▶ 注入 UserService │ └─────────────────────┘ └──────────────────────────┘