首页 > 其他分享 >gRPC简单示例

gRPC简单示例

时间:2024-03-20 21:58:07浏览次数:25  
标签:java String 示例 gRPC void greeting server 简单 protobuf

gRPC概述

gRPC是一种跨语言的RPC框架,之所以它能跨语言,是因为它基于protobuf描述对象实体和方法,最后通过protobuf编译器生成指定语言的代码。
这样,就能通过一套protobuf声明生成多种语言的相同API,对于实现跨语言的RPC通信非常便利,同时也使用protobuf作为通信的序列化协议。

如下通过一个简单的示例展示如何在Java语言中基于gRPC实现一个C/S架构的通信模型。

使用步骤

安装protobuf编译器

下载并安装protobuf编译器,并将其bin路径添加到PATH变量中,如:D:\opt\protoc-3.13.0-win64\bin

添加protobuf-java依赖

在Maven项目中添加protobuf-java依赖:

<dependency>
    <groupId>com.google.protobuf</groupId>
    <artifactId>protobuf-java</artifactId>
    <version>3.13.0</version>
</dependency>

注:这里protobuf-java的版本必须与protobuf编译器的版本保持一致!

编写protobuf描述文件

编写protobuf描述文件(在Maven项目中通常将proto文件放在src/main/proto路径下)

// hello_world.proto
syntax = "proto3";

option java_multiple_files = true;                         // 每个message类型是否生成独立的文件
option java_outer_classname = "HelloWordProto";            // 当java_multiple_files=false时生成的多个message类的包装类名
option java_package = "org.chench.extra.java.grpc.proto";  // 生成的java文件所在包名

message HelloRequest {                                     // 通过message声明一个实体类
  string greeting = 1;                                     // 类对象属性
}

message HelloResponse {
  string reply = 1;
}

service HelloService {                                     // 通过service声明rpc类
  rpc SayHello (HelloRequest) returns (HelloResponse);     // rpc方法
}

编译protobuf描述文件

编译protobuf描述文件生成对应的Java类文件,有2种方式:

方式一:进入到protobuf描述文件路径,执行命令:protoc -I=$SRC_DIR --java_out=$DST_DIR $SRC_DIR/xxx.proto(注:$SRC_DIR$DST_DIR都必须是绝对路径,否则无法正确编译)
注:命令行编译的方式默认只会生成message声明的实体类,不会生成service声明的RPC类,解决办法参考:protoc不生成.proto中的service,只生成model相关类,求助

方式二:通过Maven插件编译:

<build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.6.2</version>
        </extension>
    </extensions>
    <plugins>
        <!-- 使用如下插件编译proto文件 -->
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId>
            <artifactId>protobuf-maven-plugin</artifactId>
            <version>0.6.1</version>
            <configuration>
                <protocArtifact>com.google.protobuf:protoc:3.13.0:exe:${os.detected.classifier}</protocArtifact>
                <pluginId>grpc-java</pluginId>
                <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.4.0:exe:${os.detected.classifier}</pluginArtifact>
                <!-- 指定proto文件位置 -->
                <protoSourceRoot>${project.basedir}/src/main/proto</protoSourceRoot>
                <!-- 指定proto文件编译后生成的java文件位置 -->
                <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
                <!--设置是否在生成java文件之前清空outputDirectory的文件,默认值为true,设置为false时也会覆盖同名文件-->
                <clearOutputDirectory>false</clearOutputDirectory>
            </configuration>
            <executions>
                <execution>
                    <!--在执行mvn compile的时候会执行以下操作-->
                    <phase>compile</phase>
                    <goals>
                        <!--生成OuterClass类-->
                        <goal>compile</goal>
                        <!--生成Grpc类-->
                        <goal>compile-custom</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

在项目根目录下执行:mvn compile即可生成对应的java类。
protobuf编译生成Java类

简单rpc示例

服务端

// HelloWorldServer.java
public class HelloWorldServer {
    private static int port = 8181;
    private Server server;

    public static void main(String[] args) throws IOException, InterruptedException {
        HelloWorldServer helloWorldServer = new HelloWorldServer();
        helloWorldServer.start();
        helloWorldServer.blockUntilShutdown();
    }

    private void start() throws IOException {
        this.server = ServerBuilder.forPort(port)
                .addService(new HelloServiceImpl())
                .build()
                .start();
        logger.info(String.format("start server on port: %s", port));
        Runtime.getRuntime().addShutdownHook(new Thread(){
            @Override
            public void run() {
                logger.info("do stop...");
                try {
                    HelloWorldServer.this.stop();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                logger.info("stop done.");
            }
        });
    }

    private void stop() throws InterruptedException {
        if (this.server != null) {
            server.shutdown().awaitTermination(30, TimeUnit.SECONDS);
        }
    }

    private void blockUntilShutdown() throws InterruptedException {
        if (this.server != null) {
            this.server.awaitTermination();
        }
    }

    // 服务端实现rpc接口
    class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase {
        @Override
        public void sayHello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
            String greeting = request.getGreeting();
            logger.info(String.format("server receive greeting: %s", greeting));
            String responseMsg = new StringBuilder().append("Hello: ").append(greeting).toString();
            HelloResponse response = HelloResponse.newBuilder().setReply(responseMsg).build();
            responseObserver.onNext(response);
            responseObserver.onCompleted();
        }
    }
}

客户端

// HelloWorldClient.java
public class HelloWorldClient {
    private HelloServiceGrpc.HelloServiceBlockingStub blockingStub;

    public HelloWorldClient(Channel channel) {
        this.blockingStub = HelloServiceGrpc.newBlockingStub(channel);
    }

    public static void main(String[] args) throws IOException, InterruptedException {
        String target = "localhost:8181";
        ManagedChannel channel = ManagedChannelBuilder.forTarget(target)
                .usePlaintext()
                .build();
        HelloWorldClient helloWorldClient = new HelloWorldClient(channel);
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        String line = null;
        while ((line = reader.readLine()) != null) {
            if ("quit".equals(line.trim())) {
                channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
                System.exit(0);
            } else {
                helloWorldClient.greeting(line);
            }
        }
    }

    // 调用远程RPC接口
    private void greeting(String greeting) {
        HelloRequest request = HelloRequest.newBuilder().setGreeting(greeting).build();
        HelloResponse response = this.blockingStub.sayHello(request);
        System.out.println(String.format("received response: %s", response.getReply()));
    }
}

【参考】
grpc-java
java使用protobuf-maven-plugin的插件编译proto文件
java语言中生成gprc代码的三种方式:gradle、protoc、镜像的方式

标签:java,String,示例,gRPC,void,greeting,server,简单,protobuf
From: https://www.cnblogs.com/nuccch/p/18086174

相关文章

  • 创建自己的简单脚手架工具
    什么是脚手架?        脚手架是能帮助我们快速完成项目初始化等操作的工具。        比如在创建完react项目后的模板通常不是我们需要的,我们需要对原始模板删除一些文件才方便我们使用。因此,如果我们自己开发一个脚手架,然后下载修改后的项目模板,这样就能提高......
  • 教你简单一招解决Mac下载安装完第三方软件点开时出现“文件已损坏,应移至废纸篓”
    我们在安装一些第三方软件(破解版软件等,懂得都懂。。。)时,第一次打开时经常会出现如下情况:其实这时只需要简单两步就能“无视风险继续打开”:我们首先打开终端(终端打开方式:打开启动台(即应用菜单)--找到“其他”--点击终端),输入下面这段代码然后按回车sudospctl--master-disabl......
  • opengl日记10-opengl使用多个纹理示例
    文章目录环境代码CMakeLists.txt文件内容不变。fragmentShaderSource.fsvertexShaderSource.vsmain.cpp总结环境系统:ubuntu20.04opengl版本:4.6glfw版本:3.3glad版本:4.6cmake版本:3.16.3gcc版本:10.3.0在<opengl学习日记9-opengl使用纹理示例>的基础上,拓展使用多个纹......
  • java lambda简单用法
    一、背景介绍        lambda表达式不算是什么新奇的东西,jdk8诞生也好多年了,但是lambda表达式据我观察,在我多年的开发生涯中,周围同事用的其实不多,具体原因可能还是说不了解,习惯了过去的编程方式等等,其实自己不了解的东西不要抗拒,个人理解都是一个熟悉的过程,熟练以后也......
  • 简单网络
    交换机和路由器有什么区别?网关和路由又是什么意思交换机:把数据发送到正确的位置路由器:LAN口WAN口之间的数据转发  UDP:数据的完整性,数据的发送顺序,数据是否发送到达TCP:电话接通,互相通话,结束挂断三个关键步骤:三次握手,传输确认,四次挥手 三次握手:客户端SYN SYN+ACK  ......
  • dremio 自定义登陆以及简单sso
    一个简单的dremio集成自己外部登陆的,处理方法是通过nginx进行proxy同时开发自己的login服务,此服务调用的dremiologinapi对于自己的登陆页面调用自己开发的loginapi,然后将登陆信息写入到localstorage中,之后进行一个dremionginx访问地址的重定向因为dremio默认web登......
  • 开机设置自动mount nfs的最简单方法
    开机设置自动mountnfs的最简单方法背景公司里面很多存储其实使用的是nfs.为了保证可用,想着能够通过开机启动等方式进行挂载.这里其实不太建议使用fstab的方式进行.如果nfsserver出现了问题,可能会导致启动虚拟机变的非常缓慢.所以想法还是通过计划任务的方式来实现......
  • MySQL8设置允许简单密码
    [https://blog.51cto.com/u_16175454/9981004#:~:text=MySQL8设置允许简单密码1登录MySQL数据库首先,使用root用户登录到MySQL数据库。mysql-u,5刷新权限在修改后,需要刷新权限使更改生效。...6验证设置最后,验证设置是否生效。](https://blog.51cto.com/u_16175454/99......
  • 本题要求实现一个删除字符串中的指定字符的简单函数
    #include<stdio.h>#defineMAXN20voiddelchar(char*str,charc){  intj;  for(inti=0;*(str+i)!='\0';i++)  {    if(*(str+i)==c)    {      *(str+i)=*(str+i+1);      i--;      for......
  • 这么出人意料?电脑音频转换成MP3格式,原来这么简单
    随着数字音乐的普及,MP3格式已经成为了音频文件共享和传输的标准格式。这种有损压缩格式能将原始音频文件压缩到更小的尺寸,同时保留高质量的音频。对于电脑上的音频文件,我们有时需要将其转换成MP3格式以满足特定的需求。接下来,我们将介绍几种将电脑上的音频文件转换成MP3格式的......