Dubbo
1. 简介
1.1 Dubbo简介
Apache Dubbo 是一款微服务开发框架,它提供了 RPC通信
与 微服务治理
两大关键能力。
- 这意味着,使用 Dubbo 开发的微服务,将具备相互之间的远程发现与通信能力。
- 同时利用 Dubbo 提供的丰富服务治理能力,可以实现诸如服务发现、负载均衡、流量调度等服务治理诉求。
- 同时 Dubbo 是高度可扩展的,用户几乎可以在任意功能点去定制自己的实现,以改变框架的默认行为来满足自己的业务需求。
需要注意的是,在 Dubbo 中,我们提到服务时,通常是指 RPC 粒度的、提供某个具体业务增删改功能的接口或方法,与一些微服务概念书籍中泛指的服务并不是一个概念。
1.2 什么是RPC
RPC是远程过程调用(Remote Procedure Call)的缩写形式。
- 在A服务器上运行一个商品服务,在B服务器上运行一个订单服务。订单服务想要调用商品服务中的方法。
- 由于这两个服务不在同一个进程且不在同一台机器,只能采用远程过程调用方式获取数据。
1.2.1 RPC需要解决的问题
建立连接
- 要解决通讯的问题,主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。
- 连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
寻址
- A服务器上的应用怎么告诉底层的RPC框架,如何连接到B服务器(如主机或IP地址)以及特定的端口,方法的名称是什么,这样才能完成调用。
- 比如基于Web服务协议栈的RPC,就要提供一个endpoint+URI,或者是从UDDI服务上查找。如果是RMI调用的话,还需要一个RMI+Registry来注册服务的地址。
参数传递
- 当A服务器上的应用发起远程过程调用时,方法的参数需要通过底层的网络协议如TCP传递到B服务器。
- 由于网络协议是基于二进制的,内存中的参数的值要序列化成二进制的形式,也就是序列化(Serialize)或编组(marshal),通过寻址和传输将序列化的二进制发送给B服务器。
结果返回
- B服务器收到请求后,需要对参数进行反序列化(序列化的逆操作),恢复为内存中的表达方式,然后找到对应的方法(寻址的一部分)进行本地调用,然后得到返回值。
- 返回值还要发送回服务器A上的应用,也要经过序列化的方式发送,服务器A接到后,再反序列化,恢复为内存中的表达方式,交给A服务器上的应用
2. Dubbo入门
2.1 定义服务
需要注意的是,在 Dubbo 中,我们提到服务时,通常是指 RPC 粒度的、提供某个具体业务增删改功能的接口或方法,与一些微服务概念书籍中泛指的服务并不是一个概念。
- 服务是 Dubbo 中的核心概念,一个服务代表一组 RPC 方法的集合,服务是面向用户编程、服务发现机制等的基本单位。
- Dubbo 开发的基本流程是:用户定义 RPC 服务,通过约定的配置 方式将 RPC 声明为 Dubbo 服务,然后就可以基于服务 API 进行编程了。
- 对服务提供者来说是提供 RPC 服务的具体实现,而对服务消费者来说则是使用特定数据发起服务调用。
2.2 定义服务提供者和服务消费者
2.2.1 interface-api
分包
- 建议将服务接口、服务模型、服务异常等均放在 API 包中,因为服务模型和异常也是 API 的一部分,这样做也符合分包原则:重用发布等价原则(REP),共同重用原则(CRP)。
新建一个springBoot工程
- 该工程存放api接口和需要传输的javabean类。
person
- 网络传输需要实现序列化接口
@Data
public class Person implements Serializable {
private String name;
private String address;
}
providerService
@Component
public interface ProviderService {
Person getPerson(String name);
}
2.2.1 provide
新建一个springboot工程
- 引入相关依赖
- 引入dubbo、分包、nacos相关依赖 nacos作为注册中心合并dubbo
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.rm</groupId>
<artifactId>interface-api</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
</dependencies>
- 编写业务代码
import com.alibaba.dubbo.config.annotation.Service;
import com.rm.pojo.Person;
import com.rm.service.ProviderService;
import org.springframework.stereotype.Component;
@Component //将组件注册到Spring容器
@Service //暴露服务
public class ProviderServiceImpl implements ProviderService {
@Override
public Person getPerson(String name) {
Person person = new Person("张三", "北京市xxx区xxx楼C0405");
return person;
}
}
- 相关配置
server.port= 9000
dubbo.application.name=annotation-provider
dubbo.registry.address = nacos://127.0.0.1:8848
dubbo.registry.protocol=nacos
dubbo.protocol.name=dubbo
dubbo.protocol.port=20880
- 开启服务发现功能
@EnableDubbo // 开启服务发现功能注解
@SpringBootApplication
public class ProviderApplication {
public static void main(String[] args) {
SpringApplication.run(ProviderApplication.class, args);
}
}
- 启动该过程
查看nacos中服务实例
2.2.1 consumer
- 引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.rm</groupId>
<artifactId>interface-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.alibaba.boot</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>0.2.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>dubbo-registry-nacos</artifactId>
<version>2.6.7</version>
</dependency>
<dependency>
<groupId>com.alibaba.spring</groupId>
<artifactId>spring-context-support</artifactId>
<version>1.0.2</version>
</dependency>
</dependencies>
- 编写业务
consumerService
public interface ConsumerService {
String getPersonC( );
}
consumerServiceImpl
- 在业务接口实现类中调用生产者提供的服务
import org.springframework.stereotype.Service;
import com.alibaba.dubbo.config.annotation.Reference;
@Service
public class ConsumerServiceImpl implements ConsumerService {
@Reference //注解引用服务
ProviderService providerService1;
@Override
public String getPersonC( ) {
Person person = providerService1.getPerson("张三");
String s = JSONObject.toJSONString(person);
String res="消费者得到结果1111"+s;
return res;
}
}
- 相关配置
server.port= 9001
dubbo.application.name=annotation-consumer
dubbo.registry.address = nacos://127.0.0.1:8848
dubbo.registry.protocol=nacos
- 开启服务发现
@EnableDubbo
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
- 启动该工程
- 调用消费者接口进行测试
3. Dubbo进阶
3.1 Dubbo执行流程
服务提供方
- 将服务(接口粒度 3.0之前)暴露。添加
@Service
注解。 - 在服务提供方配置注册中心信息
dubbo:
application:
name: annotation-provider
# 协议配置,用于配置提供服务的协议信息,协议由提供方指定,消费方被动接受。
protocol:
name: dubbo
port: 20880
# 注册中心配置,用于配置连接注册中心相关信息。可以指定分组和命名空间。
registry:
protocol: nacos
address: nacos://127.0.0.1:8848?namespace=ff13be6a-1884-43d0-b578-3b325893fac4
- 在服务提供方开启服务发现功能
@EnableDubbo
,必要的话需要进行包扫描,扫描所有的服务。
服务消费方
- 在消费方配置注册中心信息
- 消费方不需要配置服务协议信息,被动接受提供方的协议即可。
dubbo:
application:
name: annotation-consumer
# 注册中心配置,用于配置连接注册中心相关信息。可以指定分组和命名空间。
registry:
protocol: nacos
address: nacos://127.0.0.1:8848?namespace=ff13be6a-1884-43d0-b578-3b325893fac4
- 使用服务,通过
@Reference
注解注入服务提供者在注册中心注册的服务。(远程注入)
- 从注册中心接口
ProviderService
的访问url - 进行远程调用RPC
- 将结果封装为一个代理对象,给变量
providerService
赋值。
@Reference
private ProviderService providerService;
- 在消费方开启服务发现功能
@EnableDubbo
,必要的话需要进行包扫描,扫描所有的服务。