Java版GRPC服务的搭建(基于SpringBoot)
基本概念
-
简介
-
RPC(remote procedure call 远程过程调用)框架实际是提供了一套机制,使得应用程序之间可以进行通信,而且也遵从server/client模型。使用的时候客户端调用server端提供的接口就像是调用本地的函数一样。
-
gRPC一开始由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。gRPC是一个高性能、开源和通用的 RPC 框架,面向移动和 HTTP/2 设计。目前提供 C、Java 和 Go 语言版本,分别是:grpc, grpc-java, grpc-go. 其中 C 版本支持 C, C++, Node.js, Python, Ruby, Objective-C, PHP 和 C# 支持。
-
gRPC 基于 HTTP/2 标准设计,带来诸如双向流、流控、头部压缩、单 TCP 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。
-
-
优点&缺点
优点 语言中立,支持多种语言 基于 IDL 文件定义服务,通过 proto3 工具生成指定语言的数据结构、服务端接口以及客户端 Stub 通信协议基于标准的 HTTP/2 设计,支持双向流、消息头压缩、单 TCP 的多路复用、服务端推送等特性,这些特性使得 gRPC 在移动端设备上更加省电和节省网络流量 序列化支持 PB(Protocol Buffer)和 JSON,PB 是一种语言无关的高性能序列化框架,基于 HTTP/2 + PB, 保障了 RPC 调用的高性能 缺点 服务治理相关能力缺失,另外负载均衡和服务发现等功能要业务扩展实现 相比较Restful API 优点更突出,gRPC可以方便地支持流式通信(理论上通过http2.0就可以使用streaming模式, 但是通常web服务的restful api似乎很少这么用,通常的流式数据应用如视频流,一般都会使用专门的协议如HLS,RTMP等,这些就不是我们通常web服务了,而是有专门的服务器应用)
代码实现
-
项目结构
-
pom依赖
<?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.4.0-SNAPSHOT</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.effsim</groupId> <artifactId>effsimservice</artifactId> <version>0.0.1-SNAPSHOT</version> <name>effsimservice</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> <os.detected.classifier>windows-x86_64</os.detected.classifier> <grpc.version>1.26.0</grpc.version> <protobuf.version>3.11.0</protobuf.version> </properties> <dependencies> <!--springboot--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <!--Springboottest--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--grpc--> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-api</artifactId> <version>1.28.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-protobuf</artifactId> <version>1.28.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-stub</artifactId> <version>1.28.0</version> </dependency> <dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>1.28.0</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> <!--Probuff工具--> <plugin> <groupId>org.xolstice.maven.plugins</groupId> <artifactId>protobuf-maven-plugin</artifactId> <version>0.6.1</version> <configuration> <pluginId>grpc-java</pluginId> <pluginArtifact> io.grpc: protoc-gen-grpc-java: 1.26.0:exe: ${os.detected.classifier} </pluginArtifact> </configuration> <executions> <execution> <goals> <!-- for protobuf --> <goal>compile</goal> <!-- for grpc --> <goal>compile-custom</goal> </goals> </execution> </executions> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>8</source> <target>8</target> </configuration> </plugin> </plugins> </build> </project>
-
服务入口
import com.effsim.main.service.GrpcStart; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; /** * *@description: 项目启动入口 *@author: Shiqinghu *@time: 2020/8/30 18:40 */ @SpringBootApplication public class EffsimserviceApplication { public static void main(String[] args) { ConfigurableApplicationContext run = SpringApplication.run(EffsimserviceApplication.class, args); GrpcStart grpcStart = (GrpcStart) run.getBean("grpcStart"); try { grpcStart.start(); } catch (Exception e) { e.printStackTrace(); } } }
-
proto文件
syntax = "proto3"; option java_package = "io.grpc.examples.helloworld"; option java_outer_classname = "HelloWorldProto"; service HelloWorld { rpc SayHello (HelloRequest) returns (HelloReply); } message HelloRequest { string name = 1; } message HelloReply { string message = 1; }
-
服务实现
package com.effsim.main.service; import io.grpc.examples.helloworld.HelloWorldGrpc; import io.grpc.examples.helloworld.HelloWorldProto; import io.grpc.stub.StreamObserver; import org.springframework.stereotype.Service; import java.util.logging.Logger; @Service public class HelloWorldServerImpl extends HelloWorldGrpc.HelloWorldImplBase { private static final Logger logger = Logger.getLogger(HelloWorldServerImpl.class.getName()); @Override public void sayHello(HelloWorldProto.HelloRequest request, StreamObserver<HelloWorldProto.HelloReply> responseObserver) { logger.info("sayHello request:" + request.getName()); responseObserver.onNext(HelloWorldProto.HelloReply.newBuilder().setMessage("留取丹心照汗青").build()); responseObserver.onCompleted(); } }
-
测试代码
package com.effsim.main.client; import com.effsim.main.comment.Constant; import io.grpc.ManagedChannel; import io.grpc.ManagedChannelBuilder; import io.grpc.StatusRuntimeException; import io.grpc.examples.helloworld.HelloWorldGrpc; import io.grpc.examples.helloworld.HelloWorldProto; import io.grpc.protobuf.ProtoUtils; import java.util.concurrent.TimeUnit; import java.util.logging.Level; import java.util.logging.Logger; public class HelloWorldClient { private static final Logger logger = Logger.getLogger(HelloWorldClient.class.getName()); public static void main(String[] args) throws Exception { ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", Constant.RUNNING_PORT) .usePlaintext() .build(); HelloWorldGrpc.HelloWorldBlockingStub helloWorldBlockingStub = HelloWorldGrpc.newBlockingStub(channel); HelloWorldProto.HelloRequest helloRequest = HelloWorldProto.HelloRequest.newBuilder().setName("人生自古谁无死").build(); logger.info("Will try to query age = " + helloRequest + " ..."); try { HelloWorldProto.HelloReply helloReply = helloWorldBlockingStub.sayHello(helloRequest); logger.info("Response: " + helloReply.getMessage()); } catch (StatusRuntimeException e) { logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus()); } finally { channel.shutdown().awaitTermination(5, TimeUnit.SECONDS); } } }
-
运行结果
以上内容均为个人学习总结梳理,如有不妥欢迎评论指点
项目地址:https://github.com/JavaSqh/grpcservice.git