Dubbo的基础教程

dubbo的定义是:

Apache Dubbo 是一款高性能、轻量级的开源RPC框架,用于构建分布式服务系统。

所以我们先来讲一下rpc。


RPC相关知识

什么是 RPC?

定义

允许程序像调用本地方法一样调用远程服务,隐藏网络细节。

生活类比

  • 🏠 本地调用:直接走到隔壁办公室找同事
  • 🌍 RPC:通过电话呼叫海外同事,但体验如同面对面交谈

RPC 核心思想

  1. 透明性

    • 开发者无需处理网络通信(序列化、传输、错误)
  2. 简化分布式系统

    • 跨机器调用 → 本地函数调用
arduino 复制代码
+-------------+      +-------------+
|   Client    |      |   Server    |
| (调用本地方法) | →网络→ | (执行远程方法) |
+-------------+      +-------------+

RPC 工作原理

四步流程

  1. 客户端代理

    • 序列化参数(如 Protobuf/JSON)
  2. 网络传输

    • 通过 HTTP/TCP 发送请求
  3. 服务端处理

    • 反序列化 → 执行业务 → 序列化结果
  4. 返回响应

    • 客户端解析结果

RPC 核心组件

组件 作用 典型技术
序列化协议 对象 ↔ 字节流 Protobuf, JSON
传输协议 数据传输通道 HTTP/2, TCP
服务发现 动态定位服务地址 ZooKeeper, Consul
负载均衡 请求分发策略 轮询, 一致性哈希

RPC 的优缺点

优点

  • 开发高效(隐藏网络细节)
  • 高性能(二进制协议)
  • 跨语言支持(如 gRPC)

缺点

  • 接口强耦合(需同步升级)
  • 调试复杂(需链路追踪工具)

讨论题

何时应避免使用 RPC? (答案:开放 API 需要高灵活性时)


常见 RPC 框架

框架 特点 适用场景
gRPC HTTP/2 + Protobuf,高性能 内部微服务
Dubbo 服务治理(熔断、降级) 企业级 Java 系统
Thrift 多协议支持(TCP/HTTP) 跨语言系统

RPC vs RESTful API

维度 RPC RESTful
协议 自定义二进制协议(高效) HTTP + 文本(灵活)
耦合性 高(接口强依赖) 低(资源导向)
场景 内部服务通信 开放 API

思考题

为什么微服务架构常用 RPC?


典型应用场景

  1. 微服务通信

    • 订单服务 → 支付服务
  2. 分布式计算

    • Spark 节点任务调度
  3. 实时系统

    • 游戏服务器状态同步

什么是Dubbo?

  • 定义:Dubbo 是一款高性能、轻量级的开源RPC框架,用于构建分布式服务系统。
  • 核心目标:简化服务间的远程调用,提供服务治理能力(负载均衡、容错、服务发现等)。
  • 适用场景:微服务架构、高并发分布式系统

核心特性

  • 高性能:基于Netty的NIO通信,支持多种协议(默认Dubbo协议)。
  • 透明化远程调用:像调用本地方法一样调用远程服务。
  • 服务治理:动态配置、流量调度、服务降级、鉴权等。

角色说明

  • Provider:服务提供者,暴露服务接口。
  • Consumer:服务消费者,调用远程服务。
  • Registry(注册中心):服务注册与发现(推荐使用Zookeeper、Nacos)。

环境搭建

创建一个这样的项目,api模块是公共模块

父项目引入公共依赖jar包

xml 复制代码
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.24</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.4.14</version>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo</artifactId>
    <version>3.3.0</version>
</dependency>
<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-context</artifactId>
     <version>6.1.10</version>
</dependency>

第一个Dubbo程序开发

这里没有使用 springboot ,用于了解 dubbo 的具体过程,如果学着比较吃力可以跳过,后面我会讲springboot下的使用

api模块开发

定义在api模块中

定义一个业务接口

java 复制代码
public interface UserService {
    boolean login(String name, String password);
}

Provider开发

引入api模块依赖

记得写成你自己的名字,不要复制粘贴

如果无法引入,先在 api 模块执行 install 命令

xml 复制代码
<dependency>
     <groupId>com.huang.dubbo</groupId>
     <artifactId>dubbo-api</artifactId>
     <version>1.0-SNAPSHOT</version>
</dependency>

实现具体的业务逻辑

实现我们刚才在api模块中定义的接口,并添加业务逻辑

java 复制代码
@Slf4j
public class UserServiceImpl implements UserService{
    @Override
    public boolean login(String name, String password) {
        log.info("用户登录,姓名:{},密码:{}", name, password);
        return false;
    }
}

编写spring配置文件

名字随便叫什么都可以

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans  
                           http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo">
<!--    名称-->
    <dubbo:application name="dubbo-provider"/>
<!--    协议和端口-->
    <dubbo:protocol name="dubbo" port="20880"/>
<!--    创建对象-->
    <bean id="userService" class="com.huang.dubbo.service.UserServiceImpl"/>
<!--    发布一个dubbo的服务,可以被消费者调用-->
    <dubbo:service interface="com.huang.dubbo.service.UserService" ref="userService"/>
​
</beans>

编写启动类

java 复制代码
public class ProviderMain {
    public static void main(String[] args) {
        // 创建 spring 工厂加载配置文件,这个文件名字要和你刚才写的文件名一样
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("application.xml");
        
        applicationContext.start();
​
        // 阻塞主线程
        try {
            new CountDownLatch(1).await();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

启动之后可以在控制台看到dubbo暴露的服务信息

其中的:dubbo://192.168.1.119:20880/com.huang.dubbo.service.UserService (注意去找你自己控制台的)

在后面会用到

项目结构

Consumer开发

引入api依赖

xml 复制代码
<dependency>
    <groupId>com.huang.dubbo</groupId>
    <artifactId>dubbo-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

创建配置文件

通过 dubbo 封装的功能获取 provider 提供的 rpc 服务

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo">
<!--    给服务起一个名字-->
    <dubbo:application name="dubbo-consumer"/>
<!--通过dubbo获取远端的 rpc 服务-->
<!--    参数说明: id:provider 中的服务对象 id ,url:provider 控制台中打印的服务信息-->
    <dubbo:reference interface="com.huang.dubbo.service.UserService" id="userService" url="dubbo://192.168.1.119:20880/com.huang.dubbo.service.UserService"/>
</beans>

创建启动类

java 复制代码
public class ConsumerApplication {
    public static void main(String[] args) {
        // 创建 spring 工厂加载配置文件
        ClassPathXmlApplicationContext applicationContext =
                new ClassPathXmlApplicationContext("application.xml");
        // 获取 bean
        UserService userService = (UserService) applicationContext.getBean("userService");
        // 获取返回值
        boolean bool = userService.login("huang", "123456");
        System.out.println("ref = " + bool);
        // 阻塞主线程
        try {
            System.in.read();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

启动程序就可以看到效果了,consumer 调用了 provider 的程序,并获得了返回值。

项目结构

解决报错问题

在 consumer 服务中,你可以找到如下的报错信息

原因:

qos是Dubbo的在线运维命令,可以对服务进行动态的配置、控制及查询,Dubbo2.5.8新版本重构了 telnet (2.0.5开始支持)模块,提供了新的 telnet 命令支持,新版本的 telnet 端口与 dubbo 协议的端口不是同一端口,默认为22222。

在同一台服务器(电脑)里面,启动 provider 时 22222 端口已经被使用,所有 consumer 启动就会报错

解决方案:

在配置文件中进行配置

xml 复制代码
<dubbo:parameter key="qos.enable" value="true"/>   <!-- 是否开启在线运维命令 -->
<dubbo:parameter key="qos.accept.foregin.ip" value="false"/>  <!-- 不允许其他机器的访问 -->
<dubbo:parameter key="qos.port" value="33333"/>   <!-- 修改port -->

springboot中的配置:

properties 复制代码
dubbo.application.qos.enable=true
dubbo.application.qos.accept.foregin.ip=false
dubbo.application.qos.port=33333

修改后的 consumer 配置文件:

xml 复制代码
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd http://dubbo.apache.org/schema/dubbo http://dubbo.apache.org/schema/dubbo/dubbo.xsd"
       xmlns:dubbo="http://dubbo.apache.org/schema/dubbo">
<!--    给服务起一个名字-->
    <dubbo:application name="dubbo-consumer">
            <dubbo:parameter key="qos.enable" value="false"/>
    </dubbo:application>
​
<!--通过dubbo获取远端的 rpc 服务-->
<!--    参数说明: id:provider 中的服务对象 id ,url:provider 控制台中打印的服务信息-->
    <dubbo:reference interface="com.huang.dubbo.service.UserService" id="userService" 
                     url="dubbo://192.168.1.119:20880/com.huang.dubbo.service.UserService"/>
​
</beans>

<dubbo:parameter key="qos.enable" value="false"/> 加到 <dubbo:application> 标签里面

可以思考一下,duboo 在这个流程中具体干了什么

基于 SpringBoot 的方式使用Dubbo

自己先创建两个springboot项目(provider和consumer),api模块可以继续使用上面的这个,也可以重新创建一个。

构建provider模块

引入依赖

xml 复制代码
<dependency>
    <groupId>com.huang.dubbo</groupId>
    <artifactId>dubbo-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>

填写配置文件

yaml 复制代码
spring:
  application:
    name: dubbo-boot-provider #应用名称
dubbo:
  protocol:
    name: dubbo #配置协议
    port: -1 #配置端口,-1 会自动选择

编写业务逻辑

创建一个类实现我们在 api 模块中定义的接口,并加上@DubboService注解

java 复制代码
@DubboService
public class UserServiceImpl implements UserService{
    @Override
    public boolean login(String name, String password) {
        System.out.println("用户登录,姓名:" + name + ",密码:" + password);
        return false;
    }
}

编写启动类

在启动类加上@EnableDubbo

java 复制代码
@EnableDubbo  // 开启 Dubbo 功能
@SpringBootApplication
public class ProviderApplication {
    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }
}

构建Consumer模块

引入依赖

xml 复制代码
<dependency>
    <groupId>com.huang.dubbo</groupId>
    <artifactId>dubbo-api</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-spring-boot-starter</artifactId>
    <version>3.3.1</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

填写配置文件

yaml 复制代码
spring:
  application:
    name: dubbo-boot-consumer #配置应用名
dubbo:
  application:
    qos-enable: false # 关闭qos

使用 springboot 的测试类进行测试

java 复制代码
@SpringBootTest
public class ConsumerTest {
​
    // url 还是在控制台找,和上面使用 spring 时是一样的
    @DubboReference(url = "dubbo://192.168.1.119:20880/com.huang.dubbo.service.UserService")
    private UserService userService;
​
    @Test
    public void test() {
        // 发起远程调用,获得返回值
        boolean ret = userService.login("huang", "123456");
        System.out.println("ret = " + ret);
    }
}

直接运行单元测试就可以看到效果了

注解解析

简单介绍一下各个注解的功能

@EnableDubbo

作用:

  • @EnableDubbo 注解用于扫描 @DubboService 并把对应的对象实例化,并发布成 RPC 服务。

    扫描路径:应用这个注解的类(启动类)所在的包及其子包

  • 如果 @DubboService 注解修饰的类没有放到@EnableDubbo 注解修饰的类当前包及其子包,可以使用@DubboComponentScan("basePackages")来指定扫描路径

  • 还可以在配置文件中进行配置

yaml 复制代码
dubbo:
  scan:
    base-packages: com.haung.dubbo # 扫描的包

@DubboService

  • 使用了@DubboService注解修饰的类型, SpringBoot 会创建这个类型的对象,并发布成 Dubbo 服务
  • @DubboService等同于@Component等注解创建对象的作用

考虑兼容性,建议实现类不仅加上@DubboService注解,也加上 @Service注解

@DubboReference

  • 在 Consumer 端,通过@DubboReference,注入远端服务的代理对象
  • @DubboReference类似于原始Spring开发中@Autowired注解的作用

等同于dubbo:reference 标签的效果

使用 Nacos 作为注册中心实现自动服务发现

演示 Nacos 作为注册中心实现自动服务发现,示例基于 Spring Boot 应用展开

添加依赖

xml 复制代码
<dependency>
    <groupId>org.apache.dubbo</groupId>
    <artifactId>dubbo-nacos-spring-boot-starter</artifactId>
    <version>3.3.0</version>
</dependency>

配置并启用 Nacos

yaml 复制代码
dubbo:
 registry:
   address: nacos://localhost:8848
   register-mode: instance # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all,默认值为 all,未来版本将切换默认值为 instance

如果需要认证:

yaml 复制代码
dubbo:
 registry:
   address: nacos://localhost:8848?username=nacos&password=nacos
   register-mode: instance

注册消费者

Dubbo 3.0.0 版本以后,增加了是否注册消费者的参数,如果需要将消费者注册到 nacos 注册中心上,需要将参数(register-consumer-url)设置为true,默认是false。

yaml 复制代码
dubbo:
  registry:
    address: nacos://localhost:8848
    register-mode: instance  # 新用户请设置此值,表示启用应用级服务发现,可选值 interface、instance、all
    parameters.register-consumer-url: true

其他的基本不变,还有就是@DubboReference直接加在属性上就可以完成注入,不需要url

相关推荐
C++业余爱好者2 小时前
ModuleNotFoundError: No module named ‘flask‘ 错误
后端·python·flask
kkk哥4 小时前
基于springboot的星之语明星周边产品销售网站(050)
java·spring boot·后端
java1234_小锋5 小时前
说说你对Java里Integer缓存的理解?
java·开发语言
虾球xz5 小时前
游戏引擎学习第175天
java·学习·游戏引擎
坚持学习永不言弃6 小时前
【IDEA】热部署SpringBoot项目
java·ide·intellij-idea
Asthenia04126 小时前
面试官问我怎么做分库分表?这是一份全面的实战解答
后端
XU磊2606 小时前
Java 集合框架:从数据结构到性能优化,全面解析集合类
java·哈希
小兵张健7 小时前
运用 AI,看这一篇就够了(上)
前端·后端·cursor
Asthenia04127 小时前
使用RocketMQ的本地消息表+事务消息/普通消息方案实现分布式事务
后端
潘多编程7 小时前
实战指南:使用 OpenRewrite 将 Spring Boot 项目从 JDK 8 升级到 JDK
java·spring boot·elasticsearch