Java版GRPC服务的搭建(基于SpringBoot)

Java版GRPC服务的搭建(基于SpringBoot)

基本概念
  1. 简介

    • 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 连接上的多复用请求等特。这些特性使得其在移动设备上表现更好,更省电和节省空间占用。

  2. 优点&缺点

    优点
    语言中立,支持多种语言
    基于 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服务了,而是有专门的服务器应用)

代码实现
  1. 项目结构
    在这里插入图片描述

  2. 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>
    
    
  3. 服务入口

    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();
    		}
    	}
    
    }
    
  4. 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;
    }
    
  5. 服务实现

    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();
        }
    }
    
    
  6. 测试代码

    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);
            }
        }
    
    
    }
    
    
  7. 运行结果

在这里插入图片描述
在这里插入图片描述

以上内容均为个人学习总结梳理,如有不妥欢迎评论指点

项目地址:https://github.com/JavaSqh/grpcservice.git

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值