【详解】后端研发常用的服务端之间通信的五种方式
五种方式总结
HTTP/HTTPS | 基于网络请求,调用方直接与服务端通信。 | RESTful API、跨平台调用 |
RPC【使用多】 | 基于二进制协议,调用方通过框架(如 Dubbo、gRPC)与服务端通信。 | 微服务架构 |
SDK(Maven)【使用多】 | 提供封装好的库,调用方通过依赖管理工具引入并直接调用。 | 第三方服务集成、工具类封装 |
WebSocket | 全双工通信,适合实时性要求高的场景。 | 实时通信(如聊天、推送) |
MQ【使用多】 | 基于异步通信,适合解耦和高并发场景。 | 分布式系统、异步任务处理 |
下面依次介绍常用的三种方式:SDK(maven)、RPC(Dubbo)、MQ(RocketMQ)。
一、以 Maven 包形式提供给对方的方式
概述
以 Maven 包的形式提供给对方是一种常见的 SDK 接入方式。这种方式将功能封装成一个可复用的库(Library),并通过 Maven 等依赖管理工具分发给调用方。调用方只需在项目中引入该包即可使用其中的功能。
特点
- 封装性好: 调用方无需关心底层实现细节,只需调用提供的 API。
- 易于分发: 通过 Maven 中央仓库或私有仓库发布,方便调用方引入。
- 版本管理: 支持语义化版本控制(如 1.0.0、1.1.0),便于升级和维护。
- 开发效率高: 调用方只需引入依赖即可使用,减少了重复开发的工作量。
适用场景
- 需要为第三方开发者提供一组功能接口。
- 希望简化调用方的集成过程。
- 功能相对独立且通用,适合封装成库。
优缺点
优点
- 封装性好:调用方无需关心底层实现细节。
- 易于分发:通过 Maven 中央仓库或私有仓库发布。
- 版本管理:支持语义化版本控制。
- 开发效率高:减少重复开发工作量。
缺点
- 耦合性:调用方需要依赖提供方的包,可能会受到版本更新的影响。
- 安全性:如果 SDK 包含敏感逻辑或数据,可能存在泄露风险。
- 灵活性不足:调用方无法轻易修改 SDK 的内部实现。
实现步骤
1. 提供方:创建 Maven 项目并打包
1.1 创建 Maven 项目
- 使用 IDE(如 IntelliJ IDEA)创建一个 Maven 项目。
- 编写核心功能代码。
1.2 配置 pom.xml
在 pom.xml
中定义项目的元信息(如 groupId
、artifactId
、version
)。
<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.example</groupId> <artifactId>example-sdk</artifactId> <version>1.0.0</version> <packaging>jar</packaging> </project>
1.3 打包
使用 Maven 打包工具生成 JAR 文件:
mvn clean package
1.4 发布到 Maven 仓库
- 中央仓库:遵循 Maven Central Repository 的发布流程。
- 私有仓库:上传到公司内部的 Nexus 或 Artifactory 私有仓库。
2. 调用方:引入 Maven 依赖
2.1 在 pom.xml
中引入依赖
调用方在自己的项目中通过 pom.xml
引入该依赖:
<dependency> <groupId>com.example</groupId> <artifactId>example-sdk</artifactId> <version>1.0.0</version> </dependency>
2.2 配置私有仓库(如果需要)
如果是私有仓库,还需要配置仓库地址:
<repositories> <repository> <id>private-repo</id> <url>https://repo.example.com/repository/maven-releases/</url> </repository> </repositories>
3. 调用方:使用 SDK 功能
调用方可以直接使用 SDK 提供的类和方法。例如:
import com.example.sdk.ExampleService; public class Main { public static void main(String[] args) { ExampleService service = new ExampleService(); String result = service.doSomething("input"); System.out.println(result); } }
分类
根据 SDK 的实现内容,可以进一步细分为以下几种:
- 功能型 SDK:提供一组功能接口,调用方可以直接调用这些接口完成特定任务。示例:支付 SDK(如支付宝、微信支付)、云服务 SDK(如阿里云、AWS)。
- 协议型 SDK:封装了与外部系统的通信协议(如 HTTP 请求、RPC 调用)。调用方通过 SDK 间接与外部系统交互,而无需关心底层通信细节。示例:Dubbo 客户端 SDK、gRPC 客户端 SDK。
- 工具型 SDK:提供一组工具类或工具方法,帮助调用方完成某些通用任务。示例:日志工具、加密工具、文件处理工具。
总结
以 Maven 包的形式提供给对方属于 SDK 方式,是一种常见的接入方式。它通过封装功能为库的形式,简化了调用方的集成过程,同时提供了良好的版本管理和分发能力。
二、以 RPC 方式(如 Dubbo)提供给对方的方式
概述
Dubbo 是阿里巴巴开源的一款高性能 Java RPC 框架,广泛应用于微服务架构中。通过 Dubbo 提供服务的方式,通常是基于服务注册与发现的机制。调用方和提供方通过 Dubbo 框架进行远程服务调用,而无需关心底层通信细节。
特点
- 透明性: 调用方像调用本地方法一样调用远程服务,无需关心底层通信细节。
- 高性能: 使用高效的二进制协议(默认为 Dubbo 协议),支持高吞吐量的服务调用。
- 服务治理: 支持负载均衡、熔断、限流等高级功能。
- 分布式支持: 适合微服务架构,能够轻松实现服务间的解耦。
适用场景
- 微服务架构中的服务间通信。
- 需要高性能、低延迟的服务调用。
- 分布式系统中需要服务注册与发现的场景。
- 内部系统之间的交互。
优缺点
优点
- 透明调用:调用方像调用本地方法一样调用远程服务。
- 高性能:使用高效的二进制协议,减少网络开销。
- 服务治理:支持负载均衡、熔断、限流等功能。
- 分布式支持:适合微服务架构,能够轻松实现服务间的解耦。
缺点
- 复杂性增加:需要引入服务注册中心(如 ZooKeeper、Nacos)和 Dubbo 框架。
- 运维成本:需要维护服务注册中心和 Dubbo 框架。
- 学习曲线:需要熟悉 Dubbo 的使用。
实现步骤
1. 提供方:发布服务
1.1 引入 Dubbo 依赖
在 pom.xml
中引入 Dubbo 和注册中心(如 Nacos 或 ZooKeeper)的 Maven 依赖。
<dependencies> <!-- Dubbo 核心依赖 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>3.2.0</version> </dependency> <!-- 注册中心依赖(以 Nacos 为例) --> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>2.2.3</version> </dependency> </dependencies>
1.2 定义服务接口
定义一个服务接口,供调用方使用。
public interface HelloService { String sayHello(String name); }
1.3 实现服务接口
提供方实现服务接口,并将其发布为 Dubbo 服务。
import org.apache.dubbo.config.annotation.DubboService; import org.apache.dubbo.config.spring.context.annotation.EnableDubbo; @DubboService(version = "1.0.0") public class HelloServiceImpl implements HelloService { @Override public String sayHello(String name) { return "Hello, " + name; } }
1.4 配置 Dubbo
在 application.properties
或 application.yml
中配置 Dubbo 和注册中心。
# Dubbo 配置 dubbo.application.name=dubbo-provider dubbo.protocol.name=dubbo dubbo.protocol.port=20880 # 注册中心配置(以 Nacos 为例) dubbo.registry.address=nacos://127.0.0.1:8848
1.5 启动服务
启动 Spring Boot 应用程序,服务将自动注册到注册中心。
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication @EnableDubbo // 启用 Dubbo public class ProviderApplication { public static void main(String[] args) { SpringApplication.run(ProviderApplication.class, args); } }
2. 调用方:调用服务
2.1 引入 Dubbo 依赖
调用方同样需要引入 Dubbo 和注册中心的 Maven 依赖。
<dependencies> <!-- Dubbo 核心依赖 --> <dependency> <groupId>org.apache.dubbo</groupId> <artifactId>dubbo</artifactId> <version>3.2.0</version> </dependency> <!-- 注册中心依赖(以 Nacos 为例) --> <dependency> <groupId>com.alibaba.nacos</groupId> <artifactId>nacos-client</artifactId> <version>2.2.3</version> </dependency> </dependencies>
2.2 引用远程服务
调用方通过 Dubbo 框架获取远程服务的代理对象,并调用其方法。
import org.apache.dubbo.config.annotation.DubboReference; import org.springframework.stereotype.Component; @Component public class HelloServiceConsumer { @DubboReference(version = "1.0.0") private HelloService helloService; public void callRemoteService() { String result = helloService.sayHello("World"); System.out.println(result); } }
2.3 配置 Dubbo
在 application.properties
或 application.yml
中配置 Dubbo 和注册中心。
# Dubbo 配置 dubbo.application.name=dubbo-consumer # 注册中心配置(以 Nacos 为例) dubbo.registry.address=nacos://127.0.0.1:8848
2.4 启动调用方
启动 Spring Boot 应用程序,调用方将从注册中心获取服务并调用。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class ConsumerApplication implements CommandLineRunner { @Autowired private HelloServiceConsumer consumer; public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } @Override public void run(String... args) throws Exception { consumer.callRemoteService(); } }
3. 配置服务注册中心
3.1 使用 Nacos 或 ZooKeeper
Dubbo 通常依赖服务注册中心(如 Nacos 或 ZooKeeper)来实现服务注册与发现。
- Nacos:轻量级服务注册中心,功能更加强大。
- ZooKeeper:经典的服务注册中心,比较老了。
3.2 配置服务地址
在 application.properties
或代码中配置服务注册中心的地址。
# 配置 Nacos 地址 dubbo.registry.address=nacos://127.0.0.1:8848 # 或配置 ZooKeeper 地址 dubbo.registry.address=zookeeper://127.0.0.1:2181
总结
通过 Dubbo 提供服务的方式属于 RPC 接入方式,它本质上是一种同步通信机制。这种方式适合微服务架构中的服务间通信,同时提供了高性能和服务治理能力。
三、以 MQ 方式(如 RocketMQ)提供给对方的方式
概述
RocketMQ 是阿里巴巴开源的一款分布式消息中间件,广泛应用于高并发、分布式系统中。通过 RocketMQ 提供服务的方式,通常是基于消息队列的异步通信机制。调用方和提供方通过消息队列进行解耦,实现高效、可靠的消息传递。
特点
- 异步通信: 调用方和提供方之间通过消息队列进行解耦。适合高并发、分布式系统的场景。
- 高性能: RocketMQ 提供了高效的二进制协议,支持高吞吐量的消息传递。
- 可靠性: 支持消息持久化、重试机制,确保消息不会丢失。
- 灵活性: 支持多种消息模式(如点对点、发布/订阅)。
适用场景
- 需要实现异步通信的系统。
- 高并发、分布式架构中的服务解耦。
- 数据流处理(如日志收集、事件驱动架构)。
- 不需要实时响应的场景。
优缺点
优点
- 异步解耦:调用方和提供方无需直接交互,降低了耦合度。
- 高并发支持:RocketMQ 能够处理大量消息,适合高并发场景。
- 可靠性高:支持消息持久化、重试机制,确保消息不丢失。
- 灵活的消息模式:支持点对点、发布/订阅等多种模式。
缺点
- 延迟较高:由于是异步通信,不适合实时性要求高的场景。
- 复杂性增加:需要引入消息队列组件,增加了系统复杂性。
- 运维成本:需要维护 RocketMQ 集群。
实现步骤
1. 提供方:生产消息
1.1 引入 RocketMQ 依赖
在 pom.xml
中引入 RocketMQ 的 Maven 依赖:
<dependency> <groupId>org.apache.rocketmq</groupId> <artifactId>rocketmq-client</artifactId> <version>4.9.3</version> </dependency>
1.2 编写生产者代码
提供方通过 RocketMQ 生产消息,并将消息发送到指定的 Topic。
import org.apache.rocketmq.client.producer.DefaultMQProducer; import org.apache.rocketmq.common.message.Message; public class RocketMQProducer { public static void main(String[] args) throws Exception { // 创建生产者实例 DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName"); producer.setNamesrvAddr("localhost:9876"); // 设置 NameServer 地址 producer.start(); // 创建消息 Message message = new Message("TopicTest", "TagA", "Hello RocketMQ".getBytes()); // 发送消息 producer.send(message); // 关闭生产者 producer.shutdown(); } }
2. 调用方:消费消息
2.1 编写消费者代码
调用方通过 RocketMQ 消费消息,并根据业务逻辑处理消息内容。
import org.apache.rocketmq.client.consumer.DefaultMQPushConsumer; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyContext; import org.apache.rocketmq.client.consumer.listener.ConsumeConcurrentlyStatus; import org.apache.rocketmq.client.consumer.listener.MessageListenerConcurrently; import org.apache.rocketmq.common.message.MessageExt; import java.util.List; public class RocketMQConsumer { public static void main(String[] args) throws Exception { // 创建消费者实例 DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("ConsumerGroupName"); consumer.setNamesrvAddr("localhost:9876"); // 设置 NameServer 地址 // 订阅 Topic consumer.subscribe("TopicTest", "*"); // 注册消息监听器 consumer.registerMessageListener(new MessageListenerConcurrently() { @Override public ConsumeConcurrentlyStatus consumeMessage(List<MessageExt> msgs, ConsumeConcurrentlyContext context) { for (MessageExt msg : msgs) { System.out.printf("Receive Message: %s%n", new String(msg.getBody())); } return ConsumeConcurrentlyStatus.CONSUME_SUCCESS; // 返回消费成功状态 } }); // 启动消费者 consumer.start(); System.out.println("Consumer Started."); } }
3. 配置 RocketMQ 环境
3.1 安装 RocketMQ
- 下载 RocketMQ 并解压。
- 启动 NameServer 和 Broker:
3.2 验证 RocketMQ
- 使用 RocketMQ 自带的工具验证是否正常运行:
4. 消息模式
4.1 点对点模式
- 每条消息只能被一个消费者消费。
- 适用于任务分配、订单处理等场景。
4.2 发布/订阅模式
- 每条消息可以被多个消费者消费。
- 适用于广播通知、日志收集等场景。
总结
通过 RocketMQ 提供服务的方式属于 消息队列接入方式,它本质上是一种异步通信机制。这种方式适合高并发、分布式系统中的服务解耦,同时提供了高可靠性和灵活性。
关注【码间烟火录】,获取更多技术干货呀!🚀
#Java##后端#