SpringBoot 集成和使用 Dubbo
Dubbo 是阿里开源的产品,采用二进制通信,相比 OpenFeign 的 http 通信,具有性能优势,可以轻松集成到 SpringBoot 和 Spring Cloud 中使用,对于性能要求比较高的场景,使用比较广泛。早期的 Dubbo 都采用 Zookeeper 作为注册中心,现在基本上大家都使用 Nacos 作为注册中心,毕竟 Dubbo 和 Nacos 都是阿里的产品,Nacos 也确实非常强大。
本篇博客主要通过代码 Demo 介绍如何使用 SpringBoot 集成 Dubbo,在博客最后会提供源代码下载。
一、准备工作
在前面的博客中,已经介绍了如何搭建 Nacos,这里不再赘述,我在自己的虚拟机中搭建了单机版 Nacos,虚拟机的 ip 地址是 192.168.216.128,搭建好之后默认不需要登录就可以访问,端口是 8848,这里全都保持不变。
阿里官方为 Dubbo 提供了一个管理后台 Dubbo Admin,网址:https://github.com/apache/dubbo-admin
下载最新的 DubboAdmin ,使用 IDEA 打开进行打包,在 dubbo-admin-server 下的 target 目录下能够获取 jar 包。
我把 jar 包名字修改为 dubbo-admin.jar ,上传到虚拟机的 /app/dubbo-admin 目录下。
将 dubbo-admin-server 项目下的 application.properties 复制一份,也上传到虚拟机的 /app/dubbo-admin 目录下。
修改 application.properties 文件,主要修改启动端口,登录的账号密码,以及其注册的 Nacos 地址,内容如下:
# 我这里使用 8181 作为 dubbo admin 网站的启动端口 server.port=8181 admin.registry.address=nacos://192.168.216.128:8848 admin.config-center=nacos://192.168.216.128:8848 admin.metadata-report.address=nacos://192.168.216.128:8848 admin.root.user.name=root admin.root.user.password=root
然后进入 /etc/systemd/system 目录下,新建一个文件 dubboAdminServer.service ,填写内容如下:
[Unit] Description=DubboAdminServer After=syslog.target network.target [Service] Type=simple #注意:ExecStart 后面的命令脚本都是写在一行中,没有手动进行换行,只是横向空间不够,自动换行了 ExecStart=/app/jdk1.8/bin/java -jar /app/dubbo-admin/dubbo-admin.jar --spring.config.location=/app/dubbo-admin/application.properties ExecStop=/bin/kill -15 $MAINPID User=root Group=root [Install] WantedBy=multi-user.target
然后执行以下命令,将 dubbo admin 安装为 linux 服务,后续维护就比较方便了
# 只要修改了 dubboAdminServer.service 文件就必须指定下面这个命令 systemctl daemon-reload # 启动服务 systemctl start dubboAdminServer # 将服务设置为开机启动 systemctl enable dubboAdminServer
我们配置的 dubbo admin 网站的端口是 8181,账号密码都是 root ,访问 http://192.168.216.128:8181
登录后界面如下:
然后访问 Nacos 的网址:http://192.168.216.128:8848/nacos
就能够看到 dubbo admin 注册的服务信息:
二、搭建工程
搭建一个 SpringBoot 父工程,里面包含 3 个子工程,如下图所示:
dubbo_common 是抽取出来的公共项目,里面是公用的实体类和接口方法
dubbo_provider 是 dubbo 服务接口的提供者,实现 dubbo_common 中定义的接口
dubbo_consumer 是 dubbo 服务的消费者,用来调用 dubbo 服务提供的 tcp 接口
父工程的 pom 文件内容如下所示,对于 3 个子工程都需要引入的 jar 包依赖,可以写在父工程的 pom 文件中:
<?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.jobs</groupId> <artifactId>springboot_dubbo</artifactId> <version>1.0</version> <modules> <module>dubbo_common</module> <module>dubbo_provider</module> <module>dubbo_consumer</module> </modules> <packaging>pom</packaging> <!-- 这里使用的 SpringBoot 的版本是 2.4.5 --> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.4.5</version> </parent> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <!-- 引入该依赖,主要在创建实体对象时,省去写 get 和 set 方法的麻烦,同时使用其日志打印功能 --> <dependencies> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> </project>
三、公共实体类和接口
由于 Dubbo 采用 Tcp 协议通信,实体类数据对象在服务器之间传输,需要进行序列化和反序列化,因此实体类必须实现 Serializable 接口。dubbo_common 的实体类和接口代码细节如下所示:
//报销费用 @Data public class Cost implements Serializable { private Integer id; //报销类别 private String category; //报销金额 private Integer money; //报销人 private Employee employee; } //员工 @Data public class Employee implements Serializable { private Integer id; //姓名 private String name; //部门 private String depart; } //本博客的 Demo 中,接口中只定义了一个方法:通过 id 获取员工信息 public interface EmployeeService { Employee getEmployeeById(Integer id); }
四、服务提供者
对于服务的提供者,由于提供的是 Tcp 接口,不需要提供 Http 接口,因此引入最简单的 SpringBoot 依赖即可:
<?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"> <parent> <artifactId>springboot_dubbo</artifactId> <groupId>com.jobs</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>dubbo_provider</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--如果该 springboot 程序只是做 dubbo 的服务端提供 tcp 接口, 不对外提供 http 接口的话,那么只需要引用 springboot 的起步依赖即可。--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--引入 dubbo 的起步依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.8</version> </dependency> <!--我们使用 nacos 作为 dubbo 的注册中心,因此需要引入以下依赖包--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-registry-nacos</artifactId> <version>2.7.8</version> </dependency> <!--引入公共的实体类和接口--> <dependency> <groupId>com.jobs</groupId> <artifactId>dubbo_common</artifactId> <version>1.0</version> </dependency> </dependencies> </project>
SpringBoot 集成 Dubbo 需要引入 dubbo-spring-boot-starter 依赖,由于使用 Nacos 作为服务的注册中心,因此需要引入 dubbo-registry-nacos 依赖,然后定义一个类 EmployeeServiceImpl 实现 dubbo_common 中的 EmployeeService 接口,在实现类上需要使用 @DubboService 即可,内容如下:
package com.jobs.service.impl; import com.jobs.pojo.Employee; import com.jobs.service.EmployeeService; import lombok.extern.slf4j.Slf4j; import org.apache.dubbo.config.annotation.DubboService; import java.util.Random; //可以指定接口的版本 //@DubboService(version = "1.0") //@DubboService(version = "2.0") @Slf4j @DubboService public class EmployeeServiceImpl implements EmployeeService { @Override public Employee getEmployeeById(Integer id) { Employee employee = new Employee(); employee.setId(id); //随机生成汉字 int temp1 = 16 + new Random().nextInt(40); int temp2 = 1 + new Random().nextInt(94); byte[] bytes = new byte[2]; bytes[0] = (byte) (0xa0 + temp1); bytes[1] = (byte) (0xa0 + temp2); String ch; try { ch = new String(bytes, "gb2312"); } catch (Exception ex) { ch = "null"; } employee.setName("小" + ch); String[] departArr = {"研发部", "财务部", "销售部", "运营部", "人事部", "宣传部"}; Random random = new Random(); int index = random.nextInt(6); employee.setDepart(departArr[index]); log.info("返回员工的 id 为:" + id); return employee; } }
然后在服务提供者 dubbo_provider 项目的 application.yml 对 dubbo 服务进行相关配置:
spring: application: name: dubbo-provider # 配置 dubbo 提供者信息:采用 dubbo 协议,指定服务的 tcp 端口 dubbo: protocol: name: dubbo port: 22222 # 使用 nacos 作为注册中心 registry: address: nacos://192.168.216.128:8848 # dubbo 扫描服务接口的包,一般扫描接口所在的包即可 scan: base-packages: com.jobs.service
这里使用 22222 作为 dubbo 服务的 tcp 端口,因此服务提供者所部署的服务器有防火墙的话,需要开放这个端口,本篇博客由于服务提供者和服务消费者都是在本地的机器上,因此不存在防火墙端口不同的问题,在实际生产环境中,服务提供者和消费者很有可能会部署在不同的服务器上。
五、服务消费者
对于服务的消费者 dubbo_consumer 来说,由于需要提供 Http 接口让我们进行测试,因此需要引入 SpringBoot 的 Web 依赖,除此之外其它的依赖包跟 dubbo_provider 提供者引入的 jar 包依赖完全相同:
<?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"> <parent> <artifactId>springboot_dubbo</artifactId> <groupId>com.jobs</groupId> <version>1.0</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>dubbo_consumer</artifactId> <properties> <maven.compiler.source>8</maven.compiler.source> <maven.compiler.target>8</maven.compiler.target> </properties> <dependencies> <!--这里的 dubbo 消费者对外提供 http 接口,用于通过浏览器测试, 因此引入了 springboot web 的依赖包--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!--引入 dubbo 的起步依赖--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-spring-boot-starter</artifactId> <version>2.7.8</version> </dependency> <!--我们使用 nacos 作为 dubbo 的注册中心,因此需要引入以下依赖包--> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo-registry-nacos</artifactId> <version>2.7.8</version> </dependency> <!--引入公共的实体类和接口--> <dependency> <groupId>com.jobs</groupId> <artifactId>dubbo_common</artifactId> <version>1.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
定义一个 Controller 提供一个 Get 请求方式的 Http 接口,供我们在浏览器地址栏上直接敲击测试使用:
package com.jobs.controller; import com.jobs.pojo.Cost; import com.jobs.pojo.Employee; import com.jobs.service.EmployeeService; import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Random; @RequestMapping("/emp") @RestController public class EmployeeController { //引用 dubbo 提供的服务,可以指定版本,指定负载均衡算法,重试次数,超时毫秒等。 //重试次数 retries 可以统一在 application.yml 进行配置,对于增删改操作,建议不要重试 //负载均衡默认为 random ,还可以配置为:roundrobin 、leastactive 、consistenthash //超时毫秒数 timeout ,可以统一在 application.yml 进行配置,在具体服务上做个性化配置 @DubboReference(loadbalance = "random") private EmployeeService employeeService; @GetMapping("/{id}") public Cost queryCostDetail(@PathVariable("id") Integer id) { Cost cost = new Cost(); cost.setId(id); String[] arr = {"打车费", "团建费", "交通费", "招待费", "电话费", "住宿费"}; Random rd = new Random(); int index = rd.nextInt(6); cost.setCategory(arr[index]); cost.setMoney(rd.nextInt(500)); Employee emp = employeeService.getEmployeeById(id); cost.setEmployee(emp); return cost; } }
然后在 application.yml 中配置上 dubbo 相关的信息,另外可以从全局的角度配置上请求超时时间、重试次数、在启动消费者程序时,是否到注册中心检查服务提供者是否存在等信息,具体内容如下:
server: port: 8888 spring: application: name: dubbo-consumer # 配置 dubbo 消费者信息 dubbo: registry: address: nacos://192.168.216.128:8848 consumer: # 关闭了启动检查,这样消费者启动时,不会到 nacos 中检查服务提供者是否存在 check: false # 建议在这里统一配置为不重试请求,对于查询来说可以在代码中单独配置重试次数 retries: 0 # 默认情况下限制请求必须在 1000 毫秒内完成,对于具体服务可以在代码中单独配置 timeout: 1000
六、验证成果
启动 dubbo_provider 和 dubbo_consumer 程序,然后在 Dubbo Admin 上都可以看到服务信息,你也可以点击详情进行查看。
在 Nacos 上能够看到【服务提供者】和【服务消费者】都注册上去了,你也可以点击详情进行查看细节:
由于我们配置的服务消费者网站启动的端口是 8888 ,因此你可以调用一下消费者提供的 http 接口进行测试。
比如调用 http://localhost:8888/emp/1
查询 id 为 1 的员工报销款信息,消费者会调用提供者的 dubbo 接口获取员工信息。
本篇博客的 Demo 源代码下载地址:https://files.cnblogs.com/files/blogs/699532/springboot_dubbo.zip
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
2022-07-11 Zookeeper 使用 Java 实现分布式协调机制