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);
    }
}

运行结果

相关推荐
yh云想7 小时前
《微服务SpringCloud架构实践指南:从Nacos到Gateway的全面解析》
spring cloud·nacos·gateway·openfeign·filter
火车叨位去194911 小时前
鱼皮项目简易版 RPC 框架开发(一)
网络·网络协议·rpc
火车叨位去194911 小时前
鱼皮项目简易版 RPC 框架开发(四)
网络·网络协议·rpc
曹朋羽1 天前
spring cloud sentinel 动态规则配置
spring·spring cloud·sentinel
火车叨位去19492 天前
鱼皮项目简易版 RPC 框架开发(五)
网络·网络协议·rpc
hello 早上好2 天前
RPC 详解
网络·网络协议·rpc
Bruce_Liuxiaowei2 天前
VNC和RPC加固措施
网络·网络协议·网络安全·rpc
你我约定有三2 天前
分布式微服务--RPC:原理、使用方式、与 HTTP/REST 的区别与选择
java·开发语言·分布式·后端·微服务·rpc
liulun2 天前
SkSurface---像素的容器:表面
网络·网络协议·rpc
火车叨位去19492 天前
鱼皮项目简易版 RPC 框架开发(六)----最后的绝唱
网络·网络协议·rpc