欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot整合GRPC微服務(wù)遠(yuǎn)程通信的實(shí)現(xiàn)示例

 更新時(shí)間:2024年02月02日 10:35:21   作者:互聯(lián)網(wǎng)小阿祥  
本文主要介紹了SpringBoot整合GRPC微服務(wù)遠(yuǎn)程通信的實(shí)現(xiàn)示例,包含gRPC的工作原理,以及如何在Spring Boot應(yīng)用中集成gRPC,具有一定的參考價(jià)值,感興趣的可以了解一下

1.什么是GRPC

在這里插入圖片描述

GRPC是RPC框架中的一種,是一個(gè)高性能,開源和通用的RPC框架,基于Protobuf序列化協(xié)議開發(fā),且支持眾多開發(fā)語(yǔ)言。

面向服務(wù)端和協(xié)議端,基于http/2設(shè)計(jì),帶來諸如雙向流,流控,頭部壓縮,單TCP連接上的多路復(fù)用請(qǐng)求等特性。這些特性使得其在移動(dòng)設(shè)備上表現(xiàn)的更好,更省電和節(jié)省空間。

在GRPC里客戶端可以向調(diào)用本地對(duì)象一樣直接調(diào)用另一臺(tái)不同機(jī)器上服務(wù)端醫(yī)用的方法,使得您能夠更容易地創(chuàng)建分布式應(yīng)用和服務(wù)。

與許多RPC系統(tǒng)類似,GRPC也是基于以下理念:定義一個(gè)服務(wù),指定其能夠被遠(yuǎn)程調(diào)用的方法。在服務(wù)端實(shí)現(xiàn)這個(gè)接口。并運(yùn)行一個(gè)GRPC服務(wù)器來處理客戶端調(diào)用。在客戶端擁有一個(gè)存根能夠向服務(wù)端一樣的方法。

2.GRPC特性以及應(yīng)用場(chǎng)景

(1)特性:

  • grpc可以跨語(yǔ)言使用。支持多種語(yǔ)言 支持C++、Java、Go、Python、Ruby、C#、Node.js、Android Java、Objective-C、PHP等編程語(yǔ)言。
  • 基于 IDL ( 接口定義語(yǔ)言)文件定義服務(wù),通過 proto3 工具生成指定語(yǔ)言的數(shù)據(jù)結(jié)構(gòu)、服務(wù)端接口以及客戶端 Stub。
  • 通信協(xié)議基于標(biāo)準(zhǔn)的 HTTP/2 設(shè)計(jì),支持雙向流、消息頭壓縮、單 TCP 的多路復(fù)用、服務(wù)端推送等特性,這些特性使得 gRPC 在移動(dòng)端設(shè)備上更加省電和節(jié)省網(wǎng)絡(luò)流量。
  • 序列化支持 PB(Protocol Buffer)和 JSON,PB 是一種語(yǔ)言無(wú)關(guān)的高性能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 調(diào)用的高性能。
  • 安裝簡(jiǎn)單,擴(kuò)展方便(用該框架每秒可達(dá)到百萬(wàn)個(gè)RPC)

(2)使用場(chǎng)景:

  • 微服務(wù):gRPC 設(shè)計(jì)用于低延遲和高吞吐量通信。 gRPC 對(duì)于效率至關(guān)重要的輕量級(jí)微服務(wù)非常有用。
  • 點(diǎn)對(duì)點(diǎn)實(shí)時(shí)通信:gRPC 對(duì)雙向流式傳輸提供出色的支持。 gRPC 服務(wù)可以實(shí)時(shí)推送消息而無(wú)需輪詢。
  • 多語(yǔ)言環(huán)境:gRPC 工具支持所有常用的開發(fā)語(yǔ)言,因此,gRPC 是多語(yǔ)言環(huán)境的理想選擇。
  • 網(wǎng)絡(luò)受限環(huán)境:gRPC 消息使用 Protobuf(一種輕量級(jí)消息格式)進(jìn)行序列化。 gRPC 消息始終小于等效的 JSON 消息。

3.GRPC大致請(qǐng)求流程

在這里插入圖片描述

  • 客戶端(gRPC Stub)調(diào)用 A 方法,發(fā)起 RPC 調(diào)用。
  • 對(duì)請(qǐng)求信息使用 Protobuf 進(jìn)行對(duì)象序列化壓縮(IDL)。
  • 服務(wù)端(gRPC Server)接收到請(qǐng)求后,解碼請(qǐng)求體,進(jìn)行業(yè)務(wù)邏輯處理并返回。
  • 對(duì)響應(yīng)結(jié)果使用 Protobuf 進(jìn)行對(duì)象序列化壓縮(IDL)。
  • 客戶端接受到服務(wù)端響應(yīng),解碼請(qǐng)求體?;卣{(diào)被調(diào)用的 A 方法,喚醒正在等待響應(yīng)(阻塞)的客戶端調(diào)用并返回響應(yīng)結(jié)果。

4.GRPC的優(yōu)點(diǎn)和缺點(diǎn)

  • 優(yōu)點(diǎn):
    • protobuf二進(jìn)制消息,性能好/效率高
    • proto文件生成目標(biāo)代碼,簡(jiǎn)單易用
    • 序列化反序列化直接對(duì)應(yīng)程序中的數(shù)據(jù)類,不需要解析后在進(jìn)行映射
    • 支持向前兼容和向后兼容
    • 支持多種語(yǔ)言,底層采用Netty實(shí)現(xiàn)
  • 缺點(diǎn):
    • GRPC尚未提供鏈接池,需要自己實(shí)現(xiàn)。
    • 尚未提供服務(wù)發(fā)現(xiàn)、負(fù)載均衡機(jī)制
    • Protobuf二進(jìn)制可讀性差

5.SpringBoot整合GRPC環(huán)境準(zhǔn)備

(1)案例背景

統(tǒng)一下單業(yè)務(wù),下單時(shí)會(huì)選擇對(duì)應(yīng)的商品和優(yōu)惠券,那么根據(jù)選擇的商品ID和優(yōu)惠券ID分別去商品微服務(wù)和優(yōu)惠券微服務(wù)進(jìn)行調(diào)用。

在這里插入圖片描述

(2)創(chuàng)建MAVEN聚合項(xiàng)目

在這里插入圖片描述

(3)父級(jí)工程pom.xml引入依賴,鎖定版本

<properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <!-- grpc版本-->
        <grpc-version>1.42.2</grpc-version>
        <!-- service和client要使用的lib版本-->
        <common-version>1.0-SNAPSHOT</common-version>
        <!--  netty版本-->
        <netty-version>4.1.65.Final</netty-version>
        <!--  Springboot版本-->
        <spring-boot.version>2.6.4</spring-boot.version>
        <!-- Springboot-grpc版本,用于server服務(wù)注解使用-->
        <grpc-spring-boot-starter.version>2.13.1.RELEASE</grpc-spring-boot-starter.version>
        <!-- maven構(gòu)建工具版本-->
        <maven-plugin-version>3.8.1</maven-plugin-version>
        <!-- lombok-->
        <lombok-version>1.18.16</lombok-version>
        <!--fastjson-->
        <fastjson.version>1.2.83</fastjson.version>
    </properties>

    <!--使用dependencyManagement聲明得到依賴子模塊不需要再進(jìn)行版本指定,直接通過父模塊指定即可,以此實(shí)現(xiàn)依賴的統(tǒng)一管理,防止出現(xiàn)依賴沖突-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>com.lixiang</groupId>
                <artifactId>common</artifactId>
                <version>${common-version}</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-netty</artifactId>
                <version>${grpc-version}</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-protobuf</artifactId>
                <version>${grpc-version}</version>
            </dependency>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-stub</artifactId>
                <version>${grpc-version}</version>
            </dependency>
            <dependency>
                <groupId>io.netty</groupId>
                <artifactId>netty-common</artifactId>
                <version>${netty-version}</version>
            </dependency>
            <!-- spring boot grpc 依賴 -->
            <dependency>
                <groupId>net.devh</groupId>
                <artifactId>grpc-client-spring-boot-starter</artifactId>
                <version>${grpc-spring-boot-starter.version}</version>
            </dependency>
            <dependency>
                <groupId>net.devh</groupId>
                <artifactId>grpc-server-spring-boot-starter</artifactId>
                <version>${grpc-spring-boot-starter.version}</version>
            </dependency>
            <dependency>
                <groupId>org.projectlombok</groupId>
                <artifactId>lombok</artifactId>
                <version>${lombok-version}</version>
            </dependency>
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>${fastjson.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

(4)創(chuàng)建common模塊

? common中引入依賴

 <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <os.detected.classifier>windows-x86_64</os.detected.classifier>
    </properties>

    <dependencies>
        <!--        Spring-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>

        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</artifactId>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
        </dependency>
        <dependency>
            <groupId>io.netty</groupId>
            <artifactId>netty-common</artifactId>
        </dependency>
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-client-spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>net.devh</groupId>
            <artifactId>grpc-server-spring-boot-starter</artifactId>
        </dependency>
        <!--        other-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </dependency>
    </dependencies>

    <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>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <!--配置protobuf插件 可參閱https://github.com/grpc/grpc-java-->
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.0</version>
                <configuration>
                    <protocArtifact>com.google.protobuf:protoc:3.19.1:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.43.1:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-plugin-version}</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

? 這塊注意這個(gè)值os.detected.classifier,獲取當(dāng)前系統(tǒng)信息,根據(jù)你們自己的電腦或者運(yùn)行環(huán)境去填寫,獲取信息的主類如下:

public class GetClassifier {
    public static void main(String[] args) {
        System.out.println(System.getProperty("os.name"));
        System.out.println(System.getProperty("os.arch"));
    }
}

在這里插入圖片描述

common模塊中創(chuàng)建一個(gè)統(tǒng)一返回工具類

在這里插入圖片描述

/**
 * @description 統(tǒng)一返回格式工具類
 * @author lixiang
 * @Version 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class BaseResponse {

    /**
     * 狀態(tài)碼 0 表示成功
     */

    private Integer code;
    /**
     * 數(shù)據(jù)
     */
    private Object data;
    /**
     * 描述
     */
    private String msg;


    /**
     *  獲取遠(yuǎn)程調(diào)用數(shù)據(jù)
     *  注意事項(xiàng):支持多單詞下劃線專駝峰(序列化和反序列化)
     * @param typeReference
     * @param <T>
     * @return
     */
    public <T> T getData(TypeReference<T> typeReference){
        return JSON.parseObject(JSON.toJSONString(data),typeReference);
    }

    /**
     * 成功,不傳入數(shù)據(jù)
     * @return
     */
    public static BaseResponse buildSuccess() {
        return new BaseResponse(0, null, null);
    }

    /**
     *  成功,傳入數(shù)據(jù)
     * @param data
     * @return
     */
    public static BaseResponse buildSuccess(Object data) {
        return new BaseResponse(0, data, null);
    }

    /**
     * 失敗,傳入描述信息
     * @param msg
     * @return
     */
    public static BaseResponse buildError(String msg) {
        return new BaseResponse(-1, null, msg);
    }

    /**
     * 自定義狀態(tài)碼和錯(cuò)誤信息
     * @param code
     * @param msg
     * @return
     */
    public static BaseResponse buildCodeAndMsg(int code, String msg) {
        return new BaseResponse(code, null, msg);
    }

}

(5)創(chuàng)建coupon-server模塊

? 添加依賴

    <dependencies>
        <dependency>
            <groupId>com.lixiang</groupId>
            <artifactId>common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-plugin-version}</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.lixiang.CouponApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

? 創(chuàng)建SpringBoot運(yùn)行主類

@SpringBootApplication
public class CouponApplication {
    public static void main(String[] objArgs)
    {
        SpringApplication.run(CouponApplication.class, objArgs);
    }
}

? 創(chuàng)建application.properties

# 定義服務(wù)名
spring.application.name=coupon-server
# 定義服務(wù)端口
server.port=8081
# 定義GRPC端口
grpc.server.port=8071

? 測(cè)試啟動(dòng)

在這里插入圖片描述

(6)創(chuàng)建product-server模塊

? 添加依賴

<dependencies>
        <dependency>
            <groupId>com.lixiang</groupId>
            <artifactId>common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-plugin-version}</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.lixiang.ProductApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

? 創(chuàng)建SpringBoot運(yùn)行主類

@SpringBootApplication
public class ProductApplication {
    public static void main(String[] objArgs)
    {
        SpringApplication.run(ProductApplication.class, objArgs);
    }
}

? 創(chuàng)建application.properties

# 定義服務(wù)名
spring.application.name=product-server
# 定義服務(wù)端口
server.port=8083
# 定義GRPC端口
grpc.server.port=8073

? 測(cè)試運(yùn)行

在這里插入圖片描述

? 這里我們需要注意一點(diǎn),我們?cè)趦?yōu)惠券服務(wù)和商品服務(wù)都定義了一個(gè)grpc.server.port,這個(gè)是用來提供給其他服務(wù)調(diào)用是寫的端口,不要和springboot本身的server.port重復(fù),否則會(huì)報(bào)錯(cuò)。

(7)創(chuàng)建order-server模塊

? 添加maven依賴

<dependencies>
        <dependency>
            <groupId>com.lixiang</groupId>
            <artifactId>common</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>${maven-plugin-version}</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.lixiang.OrderApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

? 創(chuàng)建SpringBoot運(yùn)行主類

@SpringBootApplication
public class OrderApplication {
    public static void main(String[] objArgs)
    {
        SpringApplication.run(OrderApplication.class, objArgs);
    }
}

? 創(chuàng)建application.properties

# 定義服務(wù)名
spring.application.name=order-server
# 定義服務(wù)端口
server.port=8082
# 定義GRPC端口
grpc.server.port=8072

# 定義調(diào)用商品服務(wù)的GRPC
product.server.address=localhost:8073
# 定義調(diào)用優(yōu)惠券服務(wù)的GRPC
coupon.server.address=localhost:8071

在這里插入圖片描述

6.SpringBoot整合GRPC業(yè)務(wù)開發(fā)

? ok,到目前我們所有的環(huán)境準(zhǔn)備已經(jīng)完成了,那么下面我們就開始進(jìn)入到業(yè)務(wù)的開發(fā),首先我們?cè)谙聠蔚臅r(shí)候,會(huì)傳入一個(gè)商品ID和一個(gè)優(yōu)惠券ID,那么我們要通過這兩個(gè)ID去對(duì)應(yīng)的服務(wù)查出具體的詳細(xì)信息。

(1)開發(fā)coupon-server根據(jù)ID獲取優(yōu)惠卷詳情信息

? 準(zhǔn)備CouponServer.proto文件,寫在common模塊中

在這里插入圖片描述

? CouponServer.proto內(nèi)容如下:

/**
 * 編譯工具版本
 */
syntax = "proto3";
/**
 * 指定生成實(shí)體
 */
option java_multiple_files = true;
/**
 * 指定生成接口
 */
option java_generic_services = true;
/**
 * 聲明包
 */
package com.lixiang.grpc.server;

/**
 * 商品服務(wù)proto文件
 */
option java_outer_classname = "CouponServer";

/**
 * 統(tǒng)一返回實(shí)體
 */
message CouponServerResponse {
  string message = 1;
  int32 code = 2;
  string data=3;
}

/**
 * 聲明接口
 */
service CouponService {
  rpc deductProductInventory (DeductCouponRequest) returns (CouponServerResponse);
}

/**
 * 聲明扣減商品庫(kù)存實(shí)體
 */
message DeductCouponRequest {
  int32 couponId = 1;
}

? 編寫好proto文件點(diǎn)開maven運(yùn)行protobuf插件

在這里插入圖片描述

? 運(yùn)行好之后,會(huì)發(fā)現(xiàn)target下多了一個(gè)這個(gè)包

在這里插入圖片描述

? 然后在coupon-server中開始編寫獲取優(yōu)惠券的方法,這塊我們先模擬一些優(yōu)惠券的數(shù)據(jù)。

/**
 * 優(yōu)惠券實(shí)體類
 */
@Data
public class Coupon {

    /**
     * 優(yōu)惠券ID
     */
    private Integer id;

    /**
     * 優(yōu)惠券金額
     */
    private BigDecimal amount;

    /**
     * 滿減額度
     */
    private BigDecimal fullReduction;

    /**
     * 優(yōu)惠券名稱
     */
    private String name;

    /**
     * 優(yōu)惠券可用開始時(shí)間
     */
    private LocalDateTime startTime;

    /**
     * 優(yōu)惠券結(jié)束時(shí)間
     */
    private LocalDateTime endTime;

}
public class CouponUtil {

    private final static List<Coupon> couponList = new ArrayList<>();

    static {
        Coupon coupon1 = new Coupon();
        coupon1.setAmount(new BigDecimal(50));
        coupon1.setFullReduction(new BigDecimal(300));
        coupon1.setId(1);
        coupon1.setName("滿300減50券");
        coupon1.setStartTime(LocalDateTime.parse("2022-10-20 16:25:49", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        coupon1.setEndTime(LocalDateTime.parse("2023-10-20 16:25:49", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        Coupon coupon2 = new Coupon();
        coupon2.setAmount(new BigDecimal(100));
        coupon1.setFullReduction(new BigDecimal(500));
        coupon2.setId(2);
        coupon2.setName("滿500減100券");
        coupon2.setStartTime(LocalDateTime.parse("2022-10-20 16:25:49", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        coupon2.setEndTime(LocalDateTime.parse("2023-10-20 16:25:49", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        Coupon coupon3 = new Coupon();
        coupon3.setAmount(new BigDecimal(200));
        coupon1.setFullReduction(new BigDecimal(800));
        coupon3.setId(3);
        coupon3.setName("滿800減100券");
        coupon3.setStartTime(LocalDateTime.parse("2022-10-20 16:25:49", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
        coupon3.setEndTime(LocalDateTime.parse("2023-10-20 16:25:49", DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));

        couponList.add(coupon3);
        couponList.add(coupon2);
        couponList.add(coupon1);
    }

    /**
     * 獲取具體某個(gè)優(yōu)惠券
     * @param couponId
     * @return
     */
    public static Coupon getCouponById(Integer couponId){
        return couponList.stream().filter(obj-> Objects.equals(obj.getId(), couponId)).collect(Collectors.toList()).get(0);
    }

}

? 創(chuàng)建CouponGrpcServer,繼承CouponServiceGrpc.CouponServiceImplBase,CouponServiceGrpc.CouponServiceImplBase這個(gè)類是剛剛運(yùn)行插件自動(dòng)生成的。

@GrpcService
public class CouponGrpcServer extends CouponServiceGrpc.CouponServiceImplBase {

    @Override
    public void deductProductInventory(DeductCouponRequest request, StreamObserver<CouponServerResponse> responseObserver) {
        int couponId = request.getCouponId();

        //查找優(yōu)惠券詳細(xì)信息
        Coupon coupon = CouponUtil.getCouponById(couponId);
        String jsonData = JSON.toJSONString(coupon);
        CouponServerResponse couponServerResponse = CouponServerResponse.newBuilder()
                .setCode(200)
                .setMessage("")
                .setData(jsonData)
                .build();
        responseObserver.onNext(couponServerResponse);
        responseObserver.onCompleted();
    }

? ok,這樣我們一個(gè)根據(jù)ID查詢優(yōu)惠券的信息就定義好了。

? 整體的目錄結(jié)構(gòu):

在這里插入圖片描述

(2)開發(fā)product-server根據(jù)ID獲取優(yōu)惠卷詳情信息

? product-server和coupon-server是一樣的,這里就不一一細(xì)說了,直接上代碼。

/**
 * 商品實(shí)體類
 */
@Data
public class Product {

    /**
     * 商品ID
     */
    private Integer id;

    /**
     * 商品名稱
     */
    private String name;

    /**
     * 商品價(jià)格
     */
    private BigDecimal price;

}
public class ProductUtil {

    private final static List<Product> productList = new ArrayList<>();

    static {
        Product product1 = new Product();
        product1.setId(1);
        product1.setName("互聯(lián)網(wǎng)JAVA架構(gòu)師養(yǎng)成零基礎(chǔ)到精通");
        product1.setPrice(new BigDecimal(12999));

        Product product2 = new Product();
        product2.setId(2);
        product2.setName("Python+大數(shù)據(jù)零基礎(chǔ)到精通");
        product2.setPrice(new BigDecimal(15999));

        Product product3 = new Product();
        product3.setId(3);
        product3.setName("5G云計(jì)算運(yùn)維架構(gòu)零基礎(chǔ)到精通");
        product3.setPrice(new BigDecimal(10999));

        productList.add(product1);
        productList.add(product2);
        productList.add(product3);
    }

    /**
     * 根據(jù)商品ID獲取商品詳情
     * @param productId
     * @return
     */
    public static Product getProductById(Integer productId){
        return productList.stream().filter(obj-> Objects.equals(obj.getId(), productId)).collect(Collectors.toList()).get(0);
    }

}
@GrpcService
public class ProductGrpcServer extends ProductServiceGrpc.ProductServiceImplBase {

    @Override
    public void deductProductInventory(DeductInventoryRequest request, StreamObserver<ProductServerResponse> responseObserver) {

        int productId = request.getProductId();
        Product product = ProductUtil.getProductById(productId);
        String jsonData = JSON.toJSONString(product);

        ProductServerResponse productServerResponse = ProductServerResponse.newBuilder()
                .setCode(200)
                .setMessage("")
                .setData(jsonData)
                .build();
        responseObserver.onNext(productServerResponse);
        responseObserver.onCompleted();
    }
}

? 目錄結(jié)構(gòu):

在這里插入圖片描述

(3)開發(fā)order-server模塊統(tǒng)一下單接口

? 首先我們要先配置一下GRPC的地址

在這里插入圖片描述

? 配置GrpcClientConfig

/**
 * @description Grpc Client 配置類
 * @author lixiang
 */
@Configuration
public class GrpcClientConfig {

    /**
     * 商品服務(wù)地址
     */
    @Value("${product.server.address}")
    private String productServerAddress;

    /**
     * 優(yōu)惠券服務(wù)地址
     */
    @Value("${coupon.server.address}")
    private String couponServerAddress;

    /**
     * 商品服務(wù)grpc-client
     * @return
     */
    @Bean
    public ProductServiceGrpc.ProductServiceBlockingStub getProductServerClient() {
        return ProductServiceGrpc.newBlockingStub(ManagedChannelBuilder.forTarget(productServerAddress).usePlaintext().build());
    }

    /**
     * 優(yōu)惠卷服務(wù)grpc-client
     * @return
     */
    @Bean
    public CouponServiceGrpc.CouponServiceBlockingStub getCouponServerClient() {
        return CouponServiceGrpc.newBlockingStub(ManagedChannelBuilder.forTarget(couponServerAddress).usePlaintext().build());
    }

}

? 編寫統(tǒng)一下單接口請(qǐng)求類

@Data
public class OrderConfirmRequest {

    /**
     * 支付價(jià)格
     */
    private BigDecimal totalAmount;

    /**
     * 支付類型
     */
    private String payType;

    /**
     * 支付商品的ID
     */
    private Integer productId;

    /**
     * 支付時(shí)用的優(yōu)惠券ID
     */
    private Integer couponRecordId;
}

? 編寫統(tǒng)一下單接口

@RestController
@RequestMapping(value = "/order")
public class OrderController {

    @Autowired
    private OrderService orderService;

    @PostMapping("/confirm")
    public BaseResponse confirm(@RequestBody OrderConfirmRequest orderConfirmRequest) {
        orderService.confirm(orderConfirmRequest);
        return BaseResponse.buildSuccess();
    }

}

? 編寫統(tǒng)一下單業(yè)務(wù)類

public interface OrderService {

    /**
     * 統(tǒng)一下單接口
     * @param orderConfirmRequest
     */
    void confirm(OrderConfirmRequest orderConfirmRequest);

}
@Service
@Slf4j
public class OrderServiceImpl implements OrderService{

    @Autowired
    private ProductServiceGrpc.ProductServiceBlockingStub productService;

    @Autowired
    private CouponServiceGrpc.CouponServiceBlockingStub couponService;

    @Override
    public void confirm(OrderConfirmRequest orderConfirmRequest) {
        //1.調(diào)用優(yōu)惠券服務(wù)獲取優(yōu)惠券詳情
        DeductCouponRequest deductCouponRequest = DeductCouponRequest.newBuilder()
                .setCouponId(orderConfirmRequest.getCouponRecordId())
                .build();
        CouponServerResponse couponServerResponse = couponService.deductProductInventory(deductCouponRequest);
        String couponDataStr = couponServerResponse.getData();
        JSONObject couponData = JSON.parseObject(couponDataStr);
        log.info("調(diào)用優(yōu)惠卷服務(wù)獲取的優(yōu)惠券信息:{}",couponData);

        //2.調(diào)用商品服務(wù)獲取商品詳細(xì)信息
        DeductInventoryRequest deductInventoryRequest = DeductInventoryRequest.newBuilder()
                .setProductId(orderConfirmRequest.getProductId())
                .build();
        ProductServerResponse productServerResponse = productService.deductProductInventory(deductInventoryRequest);
        String productDataStr = productServerResponse.getData();
        JSONObject productData = JSON.parseObject(productDataStr);
        log.info("調(diào)用商品服務(wù)獲取的商品信息:{}",productData);

        //3.判斷優(yōu)惠券是否在使用時(shí)間范圍內(nèi)
        long today = new Date().getTime();
        long startTime = couponData.getDate("startTime").getTime();
        long endTime = couponData.getDate("endTime").getTime();

        if(startTime>today || endTime<today){
            throw new RuntimeException("當(dāng)前優(yōu)惠券不在可用范圍內(nèi)");
        }

        //4.驗(yàn)證價(jià)格
        BigDecimal amount = couponData.getBigDecimal("amount");
        BigDecimal price = productData.getBigDecimal("price");

        if(!price.subtract(amount).equals(orderConfirmRequest.getTotalAmount())){
            throw new RuntimeException("訂單驗(yàn)價(jià)失敗");
        }

        //5.生成訂單
        log.info("當(dāng)前訂單購(gòu)買的商品為:{},原價(jià)為:{},本次消耗優(yōu)惠券:{},實(shí)際支付金額:{}",
                productData.getString("name"),productData.getBigDecimal("price"),couponData.getString("name"),orderConfirmRequest.getTotalAmount());

    }
}

? 測(cè)試全流程,啟動(dòng)三個(gè)微服務(wù)

在這里插入圖片描述

在這里插入圖片描述

? 至此,由GRPC整合微服務(wù),實(shí)現(xiàn)遠(yuǎn)程通信就已經(jīng)完成了,當(dāng)然下單業(yè)務(wù)不止這么簡(jiǎn)單,中間還有防重提交,調(diào)用三方支付,延時(shí)關(guān)單等等一些列復(fù)雜的業(yè)務(wù),這里只是給大家演示一下怎末用GRPC代替feign實(shí)現(xiàn)微服務(wù)之間的遠(yuǎn)程通信。

到此這篇關(guān)于SpringBoot整合GRPC微服務(wù)遠(yuǎn)程通信的實(shí)現(xiàn)示例的文章就介紹到這了,更多相關(guān)SpringBoot GRPC遠(yuǎn)程通信內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論