SpringBoot整合GRPC微服務遠程通信的實現示例
1.什么是GRPC
GRPC是RPC框架中的一種,是一個高性能,開源和通用的RPC框架,基于Protobuf序列化協(xié)議開發(fā),且支持眾多開發(fā)語言。
面向服務端和協(xié)議端,基于http/2設計,帶來諸如雙向流,流控,頭部壓縮,單TCP連接上的多路復用請求等特性。這些特性使得其在移動設備上表現的更好,更省電和節(jié)省空間。
在GRPC里客戶端可以向調用本地對象一樣直接調用另一臺不同機器上服務端醫(yī)用的方法,使得您能夠更容易地創(chuàng)建分布式應用和服務。
與許多RPC系統(tǒng)類似,GRPC也是基于以下理念:定義一個服務,指定其能夠被遠程調用的方法。在服務端實現這個接口。并運行一個GRPC服務器來處理客戶端調用。在客戶端擁有一個存根能夠向服務端一樣的方法。
2.GRPC特性以及應用場景
(1)特性:
- grpc可以跨語言使用。支持多種語言 支持C++、Java、Go、Python、Ruby、C#、Node.js、Android Java、Objective-C、PHP等編程語言。
- 基于 IDL ( 接口定義語言)文件定義服務,通過 proto3 工具生成指定語言的數據結構、服務端接口以及客戶端 Stub。
- 通信協(xié)議基于標準的 HTTP/2 設計,支持雙向流、消息頭壓縮、單 TCP 的多路復用、服務端推送等特性,這些特性使得 gRPC 在移動端設備上更加省電和節(jié)省網絡流量。
- 序列化支持 PB(Protocol Buffer)和 JSON,PB 是一種語言無關的高性能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 調用的高性能。
- 安裝簡單,擴展方便(用該框架每秒可達到百萬個RPC)
(2)使用場景:
- 微服務:gRPC 設計用于低延遲和高吞吐量通信。 gRPC 對于效率至關重要的輕量級微服務非常有用。
- 點對點實時通信:gRPC 對雙向流式傳輸提供出色的支持。 gRPC 服務可以實時推送消息而無需輪詢。
- 多語言環(huán)境:gRPC 工具支持所有常用的開發(fā)語言,因此,gRPC 是多語言環(huán)境的理想選擇。
- 網絡受限環(huán)境:gRPC 消息使用 Protobuf(一種輕量級消息格式)進行序列化。 gRPC 消息始終小于等效的 JSON 消息。
3.GRPC大致請求流程
- 客戶端(gRPC Stub)調用 A 方法,發(fā)起 RPC 調用。
- 對請求信息使用 Protobuf 進行對象序列化壓縮(IDL)。
- 服務端(gRPC Server)接收到請求后,解碼請求體,進行業(yè)務邏輯處理并返回。
- 對響應結果使用 Protobuf 進行對象序列化壓縮(IDL)。
- 客戶端接受到服務端響應,解碼請求體?;卣{被調用的 A 方法,喚醒正在等待響應(阻塞)的客戶端調用并返回響應結果。
4.GRPC的優(yōu)點和缺點
- 優(yōu)點:
- protobuf二進制消息,性能好/效率高
- proto文件生成目標代碼,簡單易用
- 序列化反序列化直接對應程序中的數據類,不需要解析后在進行映射
- 支持向前兼容和向后兼容
- 支持多種語言,底層采用Netty實現
- 缺點:
- GRPC尚未提供鏈接池,需要自己實現。
- 尚未提供服務發(fā)現、負載均衡機制
- Protobuf二進制可讀性差
5.SpringBoot整合GRPC環(huán)境準備
(1)案例背景
統(tǒng)一下單業(yè)務,下單時會選擇對應的商品和優(yōu)惠券,那么根據選擇的商品ID和優(yōu)惠券ID分別去商品微服務和優(yōu)惠券微服務進行調用。
(2)創(chuàng)建MAVEN聚合項目
(3)父級工程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服務注解使用--> <grpc-spring-boot-starter.version>2.13.1.RELEASE</grpc-spring-boot-starter.version> <!-- maven構建工具版本--> <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聲明得到依賴子模塊不需要再進行版本指定,直接通過父模塊指定即可,以此實現依賴的統(tǒng)一管理,防止出現依賴沖突--> <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>
? 這塊注意這個值os.detected.classifier,獲取當前系統(tǒng)信息,根據你們自己的電腦或者運行環(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)建一個統(tǒng)一返回工具類
/** * @description 統(tǒng)一返回格式工具類 * @author lixiang * @Version 1.0 */ @Data @AllArgsConstructor @NoArgsConstructor public class BaseResponse { /** * 狀態(tài)碼 0 表示成功 */ private Integer code; /** * 數據 */ private Object data; /** * 描述 */ private String msg; /** * 獲取遠程調用數據 * 注意事項:支持多單詞下劃線專駝峰(序列化和反序列化) * @param typeReference * @param <T> * @return */ public <T> T getData(TypeReference<T> typeReference){ return JSON.parseObject(JSON.toJSONString(data),typeReference); } /** * 成功,不傳入數據 * @return */ public static BaseResponse buildSuccess() { return new BaseResponse(0, null, null); } /** * 成功,傳入數據 * @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)碼和錯誤信息 * @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運行主類
@SpringBootApplication public class CouponApplication { public static void main(String[] objArgs) { SpringApplication.run(CouponApplication.class, objArgs); } }
? 創(chuàng)建application.properties
# 定義服務名 spring.application.name=coupon-server # 定義服務端口 server.port=8081 # 定義GRPC端口 grpc.server.port=8071
? 測試啟動
(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運行主類
@SpringBootApplication public class ProductApplication { public static void main(String[] objArgs) { SpringApplication.run(ProductApplication.class, objArgs); } }
? 創(chuàng)建application.properties
# 定義服務名 spring.application.name=product-server # 定義服務端口 server.port=8083 # 定義GRPC端口 grpc.server.port=8073
? 測試運行
? 這里我們需要注意一點,我們在優(yōu)惠券服務和商品服務都定義了一個grpc.server.port,這個是用來提供給其他服務調用是寫的端口,不要和springboot本身的server.port重復,否則會報錯。
(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運行主類
@SpringBootApplication public class OrderApplication { public static void main(String[] objArgs) { SpringApplication.run(OrderApplication.class, objArgs); } }
? 創(chuàng)建application.properties
# 定義服務名 spring.application.name=order-server # 定義服務端口 server.port=8082 # 定義GRPC端口 grpc.server.port=8072 # 定義調用商品服務的GRPC product.server.address=localhost:8073 # 定義調用優(yōu)惠券服務的GRPC coupon.server.address=localhost:8071
6.SpringBoot整合GRPC業(yè)務開發(fā)
? ok,到目前我們所有的環(huán)境準備已經完成了,那么下面我們就開始進入到業(yè)務的開發(fā),首先我們在下單的時候,會傳入一個商品ID和一個優(yōu)惠券ID,那么我們要通過這兩個ID去對應的服務查出具體的詳細信息。
(1)開發(fā)coupon-server根據ID獲取優(yōu)惠卷詳情信息
? 準備CouponServer.proto文件,寫在common模塊中
? CouponServer.proto內容如下:
/** * 編譯工具版本 */ syntax = "proto3"; /** * 指定生成實體 */ option java_multiple_files = true; /** * 指定生成接口 */ option java_generic_services = true; /** * 聲明包 */ package com.lixiang.grpc.server; /** * 商品服務proto文件 */ option java_outer_classname = "CouponServer"; /** * 統(tǒng)一返回實體 */ message CouponServerResponse { string message = 1; int32 code = 2; string data=3; } /** * 聲明接口 */ service CouponService { rpc deductProductInventory (DeductCouponRequest) returns (CouponServerResponse); } /** * 聲明扣減商品庫存實體 */ message DeductCouponRequest { int32 couponId = 1; }
? 編寫好proto文件點開maven運行protobuf插件
? 運行好之后,會發(fā)現target下多了一個這個包
? 然后在coupon-server中開始編寫獲取優(yōu)惠券的方法,這塊我們先模擬一些優(yōu)惠券的數據。
/** * 優(yōu)惠券實體類 */ @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)惠券可用開始時間 */ private LocalDateTime startTime; /** * 優(yōu)惠券結束時間 */ 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); } /** * 獲取具體某個優(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這個類是剛剛運行插件自動生成的。
@GrpcService public class CouponGrpcServer extends CouponServiceGrpc.CouponServiceImplBase { @Override public void deductProductInventory(DeductCouponRequest request, StreamObserver<CouponServerResponse> responseObserver) { int couponId = request.getCouponId(); //查找優(yōu)惠券詳細信息 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,這樣我們一個根據ID查詢優(yōu)惠券的信息就定義好了。
? 整體的目錄結構:
(2)開發(fā)product-server根據ID獲取優(yōu)惠卷詳情信息
? product-server和coupon-server是一樣的,這里就不一一細說了,直接上代碼。
/** * 商品實體類 */ @Data public class Product { /** * 商品ID */ private Integer id; /** * 商品名稱 */ private String name; /** * 商品價格 */ private BigDecimal price; }
public class ProductUtil { private final static List<Product> productList = new ArrayList<>(); static { Product product1 = new Product(); product1.setId(1); product1.setName("互聯網JAVA架構師養(yǎng)成零基礎到精通"); product1.setPrice(new BigDecimal(12999)); Product product2 = new Product(); product2.setId(2); product2.setName("Python+大數據零基礎到精通"); product2.setPrice(new BigDecimal(15999)); Product product3 = new Product(); product3.setId(3); product3.setName("5G云計算運維架構零基礎到精通"); product3.setPrice(new BigDecimal(10999)); productList.add(product1); productList.add(product2); productList.add(product3); } /** * 根據商品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(); } }
? 目錄結構:
(3)開發(fā)order-server模塊統(tǒng)一下單接口
? 首先我們要先配置一下GRPC的地址
? 配置GrpcClientConfig
/** * @description Grpc Client 配置類 * @author lixiang */ @Configuration public class GrpcClientConfig { /** * 商品服務地址 */ @Value("${product.server.address}") private String productServerAddress; /** * 優(yōu)惠券服務地址 */ @Value("${coupon.server.address}") private String couponServerAddress; /** * 商品服務grpc-client * @return */ @Bean public ProductServiceGrpc.ProductServiceBlockingStub getProductServerClient() { return ProductServiceGrpc.newBlockingStub(ManagedChannelBuilder.forTarget(productServerAddress).usePlaintext().build()); } /** * 優(yōu)惠卷服務grpc-client * @return */ @Bean public CouponServiceGrpc.CouponServiceBlockingStub getCouponServerClient() { return CouponServiceGrpc.newBlockingStub(ManagedChannelBuilder.forTarget(couponServerAddress).usePlaintext().build()); } }
? 編寫統(tǒng)一下單接口請求類
@Data public class OrderConfirmRequest { /** * 支付價格 */ private BigDecimal totalAmount; /** * 支付類型 */ private String payType; /** * 支付商品的ID */ private Integer productId; /** * 支付時用的優(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è)務類
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.調用優(yōu)惠券服務獲取優(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("調用優(yōu)惠卷服務獲取的優(yōu)惠券信息:{}",couponData); //2.調用商品服務獲取商品詳細信息 DeductInventoryRequest deductInventoryRequest = DeductInventoryRequest.newBuilder() .setProductId(orderConfirmRequest.getProductId()) .build(); ProductServerResponse productServerResponse = productService.deductProductInventory(deductInventoryRequest); String productDataStr = productServerResponse.getData(); JSONObject productData = JSON.parseObject(productDataStr); log.info("調用商品服務獲取的商品信息:{}",productData); //3.判斷優(yōu)惠券是否在使用時間范圍內 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("當前優(yōu)惠券不在可用范圍內"); } //4.驗證價格 BigDecimal amount = couponData.getBigDecimal("amount"); BigDecimal price = productData.getBigDecimal("price"); if(!price.subtract(amount).equals(orderConfirmRequest.getTotalAmount())){ throw new RuntimeException("訂單驗價失敗"); } //5.生成訂單 log.info("當前訂單購買的商品為:{},原價為:{},本次消耗優(yōu)惠券:{},實際支付金額:{}", productData.getString("name"),productData.getBigDecimal("price"),couponData.getString("name"),orderConfirmRequest.getTotalAmount()); } }
? 測試全流程,啟動三個微服務
? 至此,由GRPC整合微服務,實現遠程通信就已經完成了,當然下單業(yè)務不止這么簡單,中間還有防重提交,調用三方支付,延時關單等等一些列復雜的業(yè)務,這里只是給大家演示一下怎末用GRPC代替feign實現微服務之間的遠程通信。
到此這篇關于SpringBoot整合GRPC微服務遠程通信的實現示例的文章就介紹到這了,更多相關SpringBoot GRPC遠程通信內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
SpringBoot集成本地緩存性能之王Caffeine示例詳解
這篇文章主要為大家介紹了SpringBoot集成本地緩存性能之王Caffeine的示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07Java基礎知識之ByteArrayOutputStream流的使用
這篇文章主要介紹了Java基礎知識之ByteArrayOutputStream流的使用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-12-12springboot mybatis調用多個數據源引發(fā)的錯誤問題
這篇文章主要介紹了springboot mybatis調用多個數據源引發(fā)的錯誤問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-01-01Java +Tomcat + SpringMVC實現頁面訪問示例解析
這篇文章主要介紹了Java +Tomcat + SpringMVC實現頁面訪問示例解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-07-07Java并發(fā)包工具類CountDownLatch的應用詳解
CountDownLatch是Java并發(fā)包中非常實用的一個工具類,它可以幫助我們實現線程之間的同步和協(xié)作。本文主要介紹了CountDownLatch的應用場景及最佳實踐,希望對大家有所幫助2023-04-04