点击上方“芋道源码”,选择“设为星标”
管她前浪,还是后浪?
能浪的浪,才是好浪!
每天 8:55 更新文章,每天掉亿点点头发...
源码精品专栏
1. 概述
2. XML 配置
3. 注解配置
4. 参数验证
5. 自定义实现拓展点
6. 整合 Nacos
6. 整合 Sentinel
666. 彩蛋
本文在提供完整代码示例,可见 https://github.com/YunaiV/SpringBoot-Labs 的 lab-30 目录。
原创不易,给点个 Star 嘿,一起冲鸭!
1. 概述
在 2019.05.21 号,在经历了 1 年多的孵化,Dubbo 终于迎来了 Apache 毕业。在这期间,Dubbo 做了比较多的功能迭代,提供了 NodeJS、Python、Go 等语言的支持,也举办了多次社区活动,在网上的“骂声”也少了。
艿艿:事实上,大多数成熟的开源项目,都是 KPI 驱动,又或者背后有商业化支撑。
作为一个长期使用,并且坚持使用 Dubbo 的开发者,还是比较愉快的。可能,又经历了一次技术正确的选择。当然,更愉快的是,Spring Cloud Alibaba 貌似,也已经完成孵化,双剑合并,biubiubiu 。
可能胖友有些胖友对 Dubbo 不是很了解,这里艿艿先简单介绍下:
FROM Dubbo 官网
Apache Dubbo |ˈdʌbəʊ| 是一款高性能、轻量级的开源 Java RPC 框架,它提供了三大核心能力:面向接口的远程方法调用,智能容错和负载均衡,以及服务自动注册和发现。
图中,一共涉及到 5 个角色:
Registry 注册中心,用于服务的注册与发现。
Provider 服务提供者,通过向 Registry 注册服务。
Consumer 服务消费者,通过从 Registry 发现服务。后续直接调用 Provider ,无需经过 Registry 。
Monitor 监控中心,统计服务的调用次数和调用时间。
Container 服务运行容器。
FROM 《Dubbo 文档 —— 架构》
调用关系说明(注意,和上图的数字,和下面的步骤是一一对应的):
服务容器负责启动,加载,运行服务提供者。
服务提供者在启动时,向注册中心注册自己提供的服务。
服务消费者在启动时,向注册中心订阅自己所需的服务。
注册中心返回服务提供者地址列表给消费者,如果有变更,注册中心将基于长连接推送变更数据给消费者。
服务消费者,从提供者地址列表中,基于软负载均衡算法,选一台提供者进行调用,如果调用失败,再选另一台调用。
服务消费者和提供者,在内存中累计调用次数和调用时间,定时每分钟发送一次统计数据到监控中心。
本文的重心,在于一起入门 Provider 和 Consumer 的代码编写,这也是实际项目开发中,我们涉及到的角色。
Dubbo 提供了比较多的配置方式,日常开发中主要使用的是 XML 配置 和 注解配置 。我们分别会在 「2. XML 配合」 和 「3. 注解配置」 小节来入门。
考虑到现在 Dubbo 已经提供了 dubbo-spring-boot-project
项目,集成到 Spring Boot 体系中,而大家都基本采用 Spring Boot 框架,所以我们就不像 Dubbo 官方文档 一样,提供的是 Spring 环境下的示例,而是 Spring Boot 环境下。
2. XML 配置
示例代码对应仓库:lab-30-dubbo-xml-demo 。
本小节的示例,需要创建三个 Maven 项目,如下图所示:
user-rpc-service-api
项目:服务接口,定义 Dubbo Service API 接口,提供给消费者使用。详细代码,我们在 「2.1 API」 讲解。user-rpc-service-provider
项目:服务提供者,实现user-rpc-service-api
项目定义的 Dubbo Service API 接口,提供相应的服务。详细代码,我们在 「2.2 Provider」 中讲解。user-rpc-service-consumer
项目:服务消费者,会调用user-rpc-service-provider
项目提供的 Dubbo Service 服务。详细代码,我们在 「2.3 Consumer」 中讲解。
2.1 API
对应 user-rpc-service-api
项目,服务接口,定义 Dubbo Service API 接口,提供给消费者使用。
2.1.1 UserDTO
在 cn.iocoder.springboot.lab30.rpc.dto
包下,创建用于 Dubbo Service 传输类。这里,我们创建 UserDTO 类,用户信息 DTO 。代码如下:
// UserDTO.java
public class UserDTO implements Serializable {
/**
* 用户编号
*/
private Integer id;
/**
* 昵称
*/
private String name;
/**
* 性别
*/
private Integer gender;
// ... 省略 set/get 方法
}
注意,要实现 java.io.Serializable
接口。因为,Dubbo RPC 会涉及远程通信,需要序列化和反序列化。
2.1.2 UserRpcService
在 cn.iocoder.springboot.lab30.rpc.api
包下,创建 Dubbo Service API 接口。这里,我们创建 UserRpcService 接口,用户服务 RPC Service 接口。代码如下:
// UserRpcService.java
public interface UserRpcService {
/**
* 根据指定用户编号,获得用户信息
*
* @param id 用户编号
* @return 用户信息
*/
UserDTO get(Integer id);
}
2.2 Provider
对应 user-rpc-service-provider
项目,服务提供者,实现 user-rpc-service-api
项目定义的 Dubbo Service API 接口,提供相应的服务。
2.2.1 引入依赖
在 pom.xml
文件中,引入相关依赖。
<?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>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.1.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>user-rpc-service</artifactId>
<dependencies>
<!-- 引入定义的 Dubbo API 接口 -->
<dependency>
<groupId>cn.iocoder.springboot.labs</groupId>
<artifactId>user-rpc-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<!-- 引入 Spring Boot 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<!-- 实现对 Dubbo 的自动化配置 -->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo</artifactId>
<version>2.7.4.1</version>
</dependency>
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.4.1</version>
</dependency>
<!-- 使用 Zookeeper 作为注册中心 -->
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-framework</artifactId>
<version>2.13.0</version>
</dependency>
<dependency>
<groupId>org.apache.curator</groupId>
<artifactId>curator-recipes</artifactId>
<version>2.13.0</version>
</dependency>
</dependencies>
</project>
因为我们希望实现对 Dubbo 的自动化配置,所以引入
dubbo-spring-boot-starter
依赖。因为我们希望使用 Zookeeper 作为注册中心,所以引入
curator-framework
和curator-recipes
依赖。可能胖友不太了解 Apache Curator 框架,这里我们看一段简介:FROM https://www.oschina.net/p/curator
Zookeeper 的客户端调用过于复杂,Apache Curator 就是为了简化Zookeeper 客户端调用而生,利用它,可以更好的使用 Zookeeper。
-
虽然说,目前阿里正在大力推广 Nacos 作为 Dubbo 的注册中心,但是大多数团队,采用的还是 Zookeeper 为主。
对了,如果胖友不知道怎么安装 Zookeeper ,可以看看 《芋道 Zookeeper 极简入门》 文章。
2.2.2 应用配置文件
在 resources
目录下, 创建 application.yml
配置文件,添加 Dubbo 相关的配置,如下:
# dubbo 配置项,对应 DubboConfigurationProperties 配置类
dubbo:
# Dubbo 应用配置
application:
name: user-service-provider # 应用名
# Dubbo 注册中心配
registry:
address: zookeeper://127.0.0.1:2181 # 注册中心地址。个鞥多注册中心,可见 http://dubbo.apache.org/zh-cn/docs/user/references/registry/introduction.html 文档。
# Dubbo 服务提供者协议配置
protocol:
port: -1 # 协议端口。使用 -1 表示随机端口。
name: dubbo # 使用 `dubbo://` 协议。更多协议,可见 http://dubbo.apache.org/zh-cn/docs/user/references/protocol/introduction.html 文档
# Dubbo 服务提供者配置
provider:
timeout: 1000 # 【重要】远程服务调用超时时间,单位:毫秒。默认为 1000 毫秒,胖友可以根据自己业务修改
UserRpcService:
version: 1.0.0
dubbo-spring-boot-starter
依赖,会根据dubbo
配置项,实现对 Dubbo 的自动化配置。下面呢,我们来逐个配置项看看。艿艿:本小节,我们的 「XML 配置」 ,指的是使用 XML 来配置 Dubbo Service 服务。如果胖友想看纯粹的全量 XML 配置,可以看看 《Dubbo 官方文档 —— XML 配置》 。
dubbo.application
配置项,Dubbo 应用信息配置。更多属性,可见 ApplicationConfig 类。每个属性的说明,可见 《Dubbo 文档 —— dubbo:application》 。dubbo.registry
配置项,Dubbo 注册中心配置。更多属性,可见 RegistryConfig 类。每个属性的说明,可见 《Dubbo 文档 —— dubbo:registry》 。dubbo.protocol
配置项,Dubbo 服务提供者协议配置。更多属性,可见 ProtocolConfig 类。每个属性的说明,可见 《Dubbo 文档 —— dubbo:protocol》 。dubbo.provider
配置项,Dubbo 服务提供者配置。更多属性,可见 ProviderConfig 类。每个属性的说明,可见 《Dubbo 文档 —— dubbo:provider》 。dubbo.provider.UserRpcService
配置项,是我们自定义的,设置每个 Service 服务的配置。更多属性,可见 ServiceConfig 类。每个属性的说明,可见 《Dubbo 文档 —— dubbo:service》 。
2.2.3 UserRpcServiceImpl
在 cn.iocoder.springboot.lab30.rpc.service
包下,创建 Dubbo Service 实现类。这里,我们创建 UserRpcServiceImpl 类,用户服务 RPC Service 实现类。代码如下:
// UserRpcServiceImpl.java
@Service
public class UserRpcServiceImpl implements UserRpcService {
@Override
public UserDTO get(Integer id) {
return new UserDTO().setId(id)
.setName("没有昵称:" + id)
.setGender(id % 2 + 1); // 1 - 男;2 - 女
}
}
实现 UserRpcService 接口,提供 UserRpcService Dubbo 服务。
注意,在类上添加了 Spring
@Service
注解,暴露出 UserRpcServiceImpl Bean 对象。???? 后续,我们会将该 Bean 暴露成 UserRpcService Dubbo 服务,注册其到注册中心中,并提供相应的 Dubbo 服务。
2.2.4 Dubbo XML 配置文件
在 resources
目录下, 创建 dubbo.xml
配置文件,添加 Dubbo 的 Service 服务提供者,如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://dubbo.apache.org/schema/dubbo"
xmlns="http://www.springframework.org/schema/beans"
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">
<!-- 服务提供者暴露服务配置 -->
<dubbo:service ref="userRpcServiceImpl" interface="cn.iocoder.springboot.lab30.rpc.api.UserRpcService"
version="${dubbo.provider.UserRpcService.version}" />
</beans>
使用 Dubbo 自定义的 Spring
<dubbo:service>
标签,配置我们 「2.2.3 UserRpcServiceImpl」 成 UserRpcService 的 Dubbo 服务提供者。
更多 <dubbo:service>
标签的属性的说明,可见 《Dubbo 文档 —— dubbo:service》 。
2.2.5 ProviderApplication
创建 ProviderApplication 类,用于启动该项目,提供 Dubbo 服务。代码如下:
// ProviderApplication.java
@SpringBootApplication
@ImportResource("classpath:dubbo.xml")
public class ProviderApplication {
public static void main(String[] args) {
// 启动 Spring Boot 应用
SpringApplication.run(ProviderApplication.class, args);
}
}
在类上,添加
@ImportResource
注解,引入dubbo.xml
配置文件。
运行 #main(String[] args)
方法,启动项目。控制台打印日志如下:
// ... 省略其它日志
2019-12-01 22:40:34.721 INFO 64176 --- [pool-1-thread-1] .b.c.e.AwaitingNonWebApplicationListener : [Dubbo] Current Spring Boot Application is await...
看到该日志内容,意味着启动成功。
我们来使用 Zookeeper 客户端,查看 UserRpcService 服务是否注册成功。操作流程如下:
# 使用 Zookeeper 自带的客户端,连接到 Zookeeper 服务器
$ bin/zkCli.sh
# 查看 /dubbo 目录下的所有服务。
# 此时,我们查看到了 UserRpcService 服务
$ ls /dubbo
[cn.iocoder.springboot.lab30.rpc.api.UserRpcService]
# 查看 /dubbo/cn.iocoder.springboot.lab30.rpc.api.UserRpcService 目录下的存储情况。
# 此时,我们看到了 consumers 消费者信息,providers 提供者信息,routers 路由信息,configurators 配置信息。
$ ls /dubbo/cn.iocoder.springboot.lab30.rpc.api.UserRpcService
[consumers, configurators, routers, providers]
# 查看 UserRpcService 服务的节点列表
# 此时,可以看到有一个节点,就是我们刚启动的服务提供者。
$ ls /dubbo/cn.iocoder.springboot.lab30.rpc.api.UserRpcService/providers
[dubbo%3A%2F%2F10.171.1.115%3A20880%2Fcn.iocoder.springboot.lab30.rpc.api.UserRpcService%3Fanyhost%3Dtrue%