• Grpc快速实践


    记录下Grpc使用,从 grpc maven编译插件到客户端服务端实现。

    proto和Service定义

    src/main/proto/AgentModel.proto

    模型定义2个实体,参数和返回值。

    syntax = "proto3";
    option java_package = "com.jimo.grpc";
    
    message AgentInfo {
      string name = 1;
      sint32 index = 2;
    }
    
    message ReportResponse {
      bool ok = 1;
      string msg = 2;
    }
    src/main/proto/AgentService.proto
    
    在服务这边就定义一个report方法。
    
    syntax = "proto3";
    
    option java_package = "com.jimo.grpc";
    
    import "AgentModel.proto";
    
    service Agent {
      rpc report(AgentInfo) returns (ReportResponse) {}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    编译

    加入maven插件,同时编译proto文件和grpc。

            <extensions>
                <extension>
                    <groupId>kr.motd.maven</groupId>
                    <artifactId>os-maven-plugin</artifactId>
                    <version>1.6.2</version>
                </extension>
            </extensions>
            <plugins>
                <plugin>
                    <groupId>org.xolstice.maven.plugins</groupId>
                    <artifactId>protobuf-maven-plugin</artifactId>
                    <version>0.6.1</version>
                    <configuration>
                        <protocArtifact>com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
                        </protocArtifact>
                        <pluginId>grpc-java</pluginId>
                        <pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
                        </pluginArtifact>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>compile-custom</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
            </plugins>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    假如要用离线的proto执行文件,可以换成本地路径:

                <plugin>
                    <groupId>org.xolstice.maven.plugins</groupId>
                    <artifactId>protobuf-maven-plugin</artifactId>
                    <version>0.6.1</version>
                    <configuration>
                        <protocExecutable>D:\software\protoc.exe</protocExecutable>
                        <pluginId>grpc-java</pluginId>
                        <pluginExecutable>D:\software\protoc-gen-grpc-java.exe</pluginExecutable>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>compile-custom</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在命令行运行 mvn compile 可编译出protobuf和grpc的类,结构如下:

    └─target
        ├─generated-sources
        │  ├─annotations
        │  └─protobuf
        │      ├─grpc-java
        │      │  └─com
        │      │      └─jimo
        │      │          └─grpc
        │      │                  AgentGrpc.java
        │      │
        │      └─java
        │          └─com
        │              └─jimo
        │                  └─grpc
        │                          AgentModel.java
        │                          AgentService.java
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    服务端实现

    先实现服务的处理逻辑: AgentServiceImpl 继承 GRPC生成的抽象类。

    import com.jimo.grpc.AgentGrpc;
    import com.jimo.grpc.AgentModel;
    import io.grpc.stub.StreamObserver;
    
    public class AgentServiceImpl extends AgentGrpc.AgentImplBase {
    
        @Override
        public void report(AgentModel.AgentInfo request, StreamObserver<AgentModel.ReportResponse> responseObserver) {
            AgentModel.ReportResponse response = AgentModel.ReportResponse.newBuilder().setOk(true).setMsg(request.getName()).build();
            responseObserver.onNext(response);
            responseObserver.onCompleted();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    然后起一个服务:

    public static void main(String[] args) throws IOException, InterruptedException {
        Server server = ServerBuilder.forPort(8000)
                .addService(new AgentServiceImpl())
                .build().start();
        Runtime.getRuntime().addShutdownHook(new Thread(() -> {
            try {
                server.shutdown().awaitTermination(10, TimeUnit.SECONDS);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }));
        System.out.println("Listening on 8000...");
        server.awaitTermination();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    客户端实现

    客户端一般共用一个 Channel,所以传进来.然后通过 Stub调用。

    import com.jimo.grpc.AgentGrpc;
    import com.jimo.grpc.AgentModel;
    import io.grpc.Channel;
    
    public class AgentClient {
    
        private final AgentGrpc.AgentBlockingStub stub;
    
        public AgentClient(Channel channel) {
            stub = AgentGrpc.newBlockingStub(channel);
        }
    
        public void report() {
            AgentModel.ReportResponse res = stub.report(AgentModel.AgentInfo.newBuilder().setName("app01").setIndex(98).build());
            System.out.println("收到回复:" + res);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    客户端共用一个 Channel的创建和调用:

    public static void main(String[] args) throws InterruptedException {
    
        // channel最好创建一个,可以共用,是线程安全的
        ManagedChannel channel = ManagedChannelBuilder
                .forAddress("localhost", 8000)
                // 默认是SSL/TLS,这里不用
                .usePlaintext()
                .build();
    
        AgentClient agentClient = new AgentClient(channel);
        agentClient.report();
        agentClient.report();
    
        // channel默认会等待一段时间关闭,如果不用了最好及时关闭,否则会占用TCP连接
        channel.shutdownNow().awaitTermination(5, TimeUnit.SECONDS);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    更多问题

    1、我们需要对请求做拦截,做一些AOP的事情怎么弄?—-用 ClientInterceptor

    2、在上面的客户端使用了 AgentGrpc.newBlockingStub(channel),还有好几种Stub,有什么区别,怎么使用?

    3、客户端和服务端通信的网络和协议是如何实现的?为什么客户端的Channel会自动关闭?

    先把坑埋好。

  • 相关阅读:
    【毕业设计】深度学习行人车辆流量计数系统 - 目标检测 python
    Docker Buildx使用教程:使用Buildx构建多平台镜像
    Flink 检查点(Checkpoint)
    优化器的使用
    信息化与数字化的区别,我掺和一把
    Java后端开发技术选型
    我的大二web课程设计 使用HTML做一个简单漂亮的页面(纯html代码)
    【深度学习实验】卷积神经网络(七):实现深度残差神经网络ResNet
    Code Former安装及使用
    SpringBoot集成文件 - 如何基于POI-tl和word模板导出庞大的Word文件?
  • 原文地址:https://blog.csdn.net/jimo_lonely/article/details/125491027