Nacos + Dubbo3 实现微服务的Rpc调用

文章目录

概念整理

基本概念

  1. RPC可以理解为一种网络服务调用形式,具有服务提供方,服务调用方,调用功能,请求参数和响应参数的类似概念
  2. RPC有多种实现途径或组合框架,Nacos + Dubbo只是一种比较简单的实现方式
  3. 相比于HTTP请求
    1. RPC更适合在微服务节点之间进行高效的信息传输。原因之一是,在OSI模型中HTTP在第七层,RPC在第五层,所以RPC实现更加底层,处理过程更加简单,通讯效率更高。
    2. RPC必须要有【服务注册中心】这个组成部分,对提供者和消费者之间提供通讯桥梁,即提供者和消费者之间没有直连关系:
      1. 提供者:提供RPC服务并注册到服务中心
      2. 消费者:访问服务中心调用其中的RPC服务

概念助记

以下概念不是官方解释,仅为了方便第一次接触RPC时,方便理解RPC的相关概念

前提

  1. 对于普通Spring Boot项目在后台传输信息时,服务调用方(下称消费者)可以直接访通过服务提供方(下称提供者)提供的公开URL在java后台用Fegin、RestTemplate或者HttpClient工具发起形如get http:\\目标节点IP:端口\functionUrl?param = xxxx这样的请求
  2. 在Spring Cloud项目里,引入了【服务中心】,各节点都注册到中心里,所以调用URL变成了get http:\\目标服务在服务中心的名字\functionUrl?param = xxxx
  3. 可以简单理解HTTP请求操作的中心就是URL,而RPC使用接口Interface(就是java原生的那个interface类型)替换对URL的操作

RPC与HTTP类比

RPC HTTP
提供者 Spring Cloud节点 Spring Cloud或Spring Boot节点
消费者 Spring Cloud节点 Spring Cloud或Spring Boot节点
服务发现中心 必选 可选
调用目标名 服务中心注册名 服务中心注册名或目标IP+端口
调用URL的PathURL 接口类的方法名 PathURL
请求参数 接口方法入参 path或者body参数
响应结果 接口方法返回值 请求Response的body
请求包含其他内容 header,状态参数等

RPC接口类的一些理解

  1. RPC接口从代码层面定义一个节点功能的名称,入参、返回值等结果,相当于定义HTTP请求的RequestMap的路径和Controller的参数和返回值
  2. RPC接口对提供者和调用者同时可见
  3. RPC接口在提供者内部实现具体的业务逻辑,即存在Imp类,完成具体的业务功能
  4. RPC接口在调用者内部没有实现类,但可以像Mybatis的Mapper接口一样,注入并调用接口方法实现接口功能 ,可以理解为在Dubbo和Nacos的支持下(其他框架也可以),调用者内部的接口,生成了一个动态代理实例,这个实例的内部逻辑就是发起RPC网络请求,去执行提供者实现的接口类逻辑。使用起来可以类比Mybatis的Mapper接口,只定义Mapper接口,但这个接口使用时可以被注入,调用方法时也有具体的实现逻辑。

实例代码

主体结构

父项目

  1. 父项目没有任何java,yml文件,仅利用pom.xml限制当前项目各个模块之间的版本统一性
  2. 具体的Nacos,SpringBoot,Cloud,Dubbo版本情况如下 (版本一定要配套,否则会有各种启动异常)
    1. JDK 8
    2. Spring boot 2.7.18
    3. Spring Cloud 2021.0.6
    4. Spring Cloud Alibaba 2021.0.6.0,内置 Nacos client 2.2.0
    5. dubbo:3.2.14

使用Dubbo 3版本,引入依赖、项目配置和代码注解都会与Dubbo2有大差异,一定要注意。

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.18</version>
    </parent>
    <packaging>pom</packaging>
    <groupId>com</groupId>
    <artifactId>dubbo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>dubbo</name>
    <description>dubbo</description>
    <properties>
        <java.version>8</java.version>
        <spring-boot.version>2.7.18</spring-boot.version>
        <spring-cloud-alibaba.version>2021.0.6.0</spring-cloud-alibaba.version>
        <spring.cloud.version>2021.0.6</spring.cloud.version>
        <dubbo.version>3.2.14</dubbo.version>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>
    <!-- 统一管理,配置在此模块下的,子模块要引入依赖必须声明groupId和artifactId,不需要声明版本-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring.cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>${spring-cloud-alibaba.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.apache.dubbo</groupId>
                <artifactId>dubbo-bom</artifactId>
                <version>${dubbo.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

公共接口项目

  1. 项目结构
  2. 定义公共接口
java 复制代码
package com.common;

public interface IHelloService {

    String provider(String content);
}
  1. POM文件里可以不用实现任何Dependence
  2. 不需要在Application.yml中配置任何参数

提供者项目

项目结构

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">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dubbo-provider</artifactId>
    <version>1.0</version>
    <parent>
        <groupId>com</groupId>
        <artifactId>dubbo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../../dubbo</relativePath>
    </parent>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>com</groupId>
            <artifactId>dubbo-interface</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

特别注意

  1. Nacos的实现包含了nacos-config和nacos-discovery两个包

  2. dubbo-spring-boot-starter的groupId是apache,不是alibaba

配置文件实现

yaml 复制代码
# SpringCloud服务注册和发现
server:
  port: 8881
spring:
  cloud:
    nacos: #2.3以后Nacos版本都建议配置discovery和config两个
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848

#Dubbo服务实现类的扫描基准包路径
dubbo:
  application:
    name: dubbo-provider
  scan:
    base-packages: com.provider
  #Dubbo服务暴露的协议配置
  protocol:
    name: dubbo #name为协议名称,默认为dubbo
    port: -1 #port为协议端口(-1 表示自增端口,从 20880 开始)
  registry: # 必须包含此节点配置
    address: nacos://localhost:8848 # 注意应该nacos开头,否则没法注册

公共接口实现

java 复制代码
package com.provider;

import com.common.IHelloService;
import org.apache.dubbo.config.annotation.DubboService;

@DubboService //该注解说明当前实现类为RPC服务类
public class HelloServiceImp implements IHelloService {
    @Override
    public String provider(String content) {
        System.out.println("into Service1Imp");
        return "服务提供者-" + content;
    }
}

程序入口配置

java 复制代码
package com.provider;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@EnableDiscoveryClient
@SpringBootApplication
//不用再使用@EnableDubbo注解
public class ProviderApplication {

    public static void main(String[] args) {
        SpringApplication.run(ProviderApplication.class, args);
    }

}

启动项目检查是否可以注入到Nacos

消费者项目

项目结构

这里使用JunitTest来验证RPC是否可以正常调用

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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <artifactId>dubbo-customer</artifactId>
    <version>1.0</version>

    <parent>
        <groupId>com</groupId>
        <artifactId>dubbo</artifactId>
        <version>0.0.1-SNAPSHOT</version>
        <relativePath>../../dubbo</relativePath>
    </parent>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-bootstrap</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.apache.dubbo</groupId>
            <artifactId>dubbo-spring-boot-starter</artifactId>
        </dependency>

        <dependency>
            <groupId>com</groupId>
            <artifactId>dubbo-interface</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

再次强调

  1. Nacos的实现包含了nacos-config和nacos-discovery两个包

  2. dubbo-spring-boot-starter的groupId是apache,不是alibaba

配置文件实现

yaml 复制代码
server:
  port: 8882
#Spring配置
spring:
  application:
    name: dubbo-consumer
  cloud:
    discovery: #禁止该服务注册到Nacos服务列表中
      register-enabled: false
  nacos:
    discovery:
      server-addr: localhost:8848
dubbo:
  cloud:
    subscribed-services: dubbo-provider #表示要订阅服务的服务名,若需订阅多应用,使用","分割。
  protocol:
    name: dubbo
    port: 20881 # 同一台物理机既要启动提供者又要启动消费者时,必须指定dubbo端口号,如果用默认端口则会冲突
  registry: #必须要配置此属性,否则会启动异常
    address: nacos://localhost:8848  #必须是nacos开头
  application:
    qosEnable: false # 该参数默认为true,如果不手工改为false,则需要修改qosPort默认端口号,防止端口冲突
#    qosPort: 8883
#    qosAcceptForeignIp: false

再次强调

dubbo3版本的消费者必须追以下属性

  1. dubbo.registry.address:
  2. dubbo.application.qosEnable:
  3. dubbo.application.qosPort
  4. dubbo.application.qosAcceptForeignIp

关于Qos配置问题,可以参考这篇博客Dubbo启动时qos-server can not bind localhost:22222错误解决

注册RPC服务类实例

java 复制代码
package com.customer;

import com.common.IHelloService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloTest {

    @DubboReference
    private IHelloService helloService;

    @Test
    public void RPCTest(){
        String result = helloService.provider("Lily");
        System.out.println("运行结果: " + result);
    }
}

运行结果

相关推荐
瑞金彭于晏14 小时前
微服务架构与传统的单体架构有什么区别?微服务架构(Spring Cloud + Maven)强在哪?
spring cloud·微服务·架构
极客Kimi17 小时前
Dubbo RPC 原理
网络协议·rpc·dubbo
代码洁癖症患者17 小时前
玩转 Netty : 如何设计高性能RPC通信组件
网络·网络协议·rpc
蝴蝶不愿意19 小时前
Docker基础-常见命令
java·笔记·学习·spring cloud·docker
别惹CC1 天前
Spring Boot 3 整合 Spring Cloud Gateway 工程实践
java·spring boot·后端·spring cloud·gateway
红豆和绿豆2 天前
如何实现将http请求转化为rpc请求
网络协议·http·rpc
mit6.8242 天前
[实现Rpc] 客户端 | Requestor | RpcCaller的设计实现
c++·rpc
zzyh1234562 天前
springcloud负载均衡策略有哪些
java·spring cloud·负载均衡
希忘auto3 天前
Spring Cloud之注册中心之Nacos的安装
java·后端·spring·spring cloud