RPC之gRPC的使用

本文介绍在Java中使用gRPC的过程。一般来说,主要包含以下的三个步骤
1)在.proto文件中定义提供的服务
2)使用protocol buffer编译器编译文件
3)使用gRPC API来创建服务端和客户端,并进行调用。

下载和安装需要的软件

1)Protocol Buffers
结构化数据序列化机制
https://github.com/protocolbuffers/protobuf/releases
使用示例:

protoc --java_out=./ *.proto

2)protoc-gen-grpc-java
用于生成RPC通信代码
http://jcenter.bintray.com/io/grpc/protoc-gen-grpc-java/
使用示例【使用Protobuf-Plugin机制】:

protoc --plugin=protoc-gen-grpc-java=protoc-gen-grpc-java-1.19.0-windows-x86_64.exe --grpc-java_out=./ *.proto

使用Maven构建gRPC

1)修改pmo.xml

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <protobuf.version>3.7.0</protobuf.version>
        <grpc.version>1.19.0</grpc.version>
    </properties>

    <dependencies>      
        <dependency>
          <groupId>io.grpc</groupId>
          <artifactId>grpc-netty-shaded</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>
        <!-- 确保运行时的版本号与protoc的版本号匹配(或更新) -->
        <dependency>
          <groupId>com.google.protobuf</groupId>
          <artifactId>protobuf-java</artifactId>
          <version>${protobuf.version}</version>
        </dependency>
        <!-- 如果您想使用像JsonFormat这样的特性 ,则添加以下依赖-->
        <dependency>
          <groupId>com.google.protobuf</groupId>
          <artifactId>protobuf-java-util</artifactId>
          <version>${protobuf.version}</version>
        </dependency>
    </dependencies>
    <build>
        <extensions>
            <extension>
                <!-- 该插件的说明参考 https://github.com/trustin/os-maven-plugin -->
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.6.1</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.6.1</version>
                <configuration>
                    <!-- proto文件的所在路径 -->
                    <!-- <protoSourceRoot>${project.basedir}/src/main/resources/proto</protoSourceRoot> -->
                    <!-- 编译后java文件的输出路径,默认为${project.build.directory}/generated-sources/protobuf/java -->
                    <!--<outputDirectory> ${project.build.directory}/generated-sources/protobuf/java</outputDirectory> -->
                    <!-- 制定protoc编译器路径 -->
                    <!-- <protocExecutable></protocExecutable> -->
                    <!-- 定义生成的java文件输出路径 -->
                    <!--<outputDirectory>${project.build.sourceDirectory}</outputDirectory> -->
                    <!--设置是否在生成java文件之前清空outputDirectory的文件,默认值为true,设置为false时也会覆盖同名文件 -->
                    <clearOutputDirectory>false</clearOutputDirectory>
                    <protocArtifact>com.google.protobuf:protoc:${protobuf.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>
    </build>

默认情况下,该插件会查找 src/main/proto路径下的proto文件。该在路径下的任何子文件夹都会作为proto文件中使用的包路径。

2)在src/main/proto下创建proto文件

syntax = "proto3";

package com.ultrapower.ioss.webdriver.proto;

option java_outer_classname = "HarLogRpc";

message HarLogResovleRequest{
    string url = 1 ;
    string file_name = 2;
    string file_dir = 3;
    string context = 4;
}

message HarLogResovleResponse{
    int32 code = 1 ;
}

service HarLogService{
    rpc ResovleHarLog(HarLogResovleRequest) returns (HarLogResovleResponse);
}

3)编译文件

mvn protobuf:compile 
或
mvn compile

在target\generated-sources\protobuf下会生成以下两个文件夹
RPC之gRPC的使用
其中java文件夹下面包含了我们定义的message,而grpc-java下存放的是服务端和客户端都要使用的service。
基于上面的proto文件,生成了两个java文件

1,HarLogServiceGrpc.java   位于grpc-java下
2,HarLogRpc.java  位于java下

4)完成代码

首先我们实现服务端的代码

package com.ultrapower.ioss.webdriver.proto;

import com.ultrapower.ioss.webdriver.proto.HarLogRpc.HarLogResovleRequest;
import com.ultrapower.ioss.webdriver.proto.HarLogRpc.HarLogResovleResponse;

import io.grpc.stub.StreamObserver;

public class HarLogServiceImpl extends HarLogServiceGrpc.HarLogServiceImplBase {

    @Override
    public void resovleHarLog(HarLogResovleRequest request, StreamObserver<HarLogResovleResponse> responseObserver) {
        String fileName = request.getFileName() ;
        responseObserver.onNext(HarLogResovleResponse.newBuilder().setCode(200).build());
        //表示已经处理完成
        responseObserver.onCompleted();
    }
}

启动服务端

public class Startup {
    private Server server;
    private int port = 8888;

    public void start() throws IOException {
        server = ServerBuilder.forPort(port)
                .addService(new HarLogServiceImpl())
                .build()
                .start();

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                Startup.this.stop();
            }
        });
    }

    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

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

    public static void main(String[] args) throws Exception {
        final Startup server = new Startup();
        server.start();
        server.blockUntilShutdown();
    }
}

创建基于Java的客户端

public class Client {

    private final ManagedChannel channel;

    private final HarLogServiceGrpc.HarLogServiceBlockingStub blockingStub;

    /**
     *  创建服务端连接,并创建“桩”
     * */
    public Client(String host, int port) {
        channel = NettyChannelBuilder.forAddress(host, port).negotiationType(NegotiationType.PLAINTEXT).build();
        blockingStub = HarLogServiceGrpc.newBlockingStub(channel);
    }

    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    /**
     *  向服务端发送请求
     * */
    public void resovleHarLog() {
        try {
            HarLogResovleRequest request = HarLogResovleRequest.newBuilder().setUrl("www.baidu.com").setFileName("test").build();
            HarLogResovleResponse response = blockingStub.resovleHarLog(request) ;
            System.out.println("result from server: " + response.getCode());
        } catch (RuntimeException e) {
            System.out.println("RPC failed:" + e.getMessage());
            return;
        }
    }

    public static void main(String[] args) throws Exception {
        Client client = new Client("127.0.0.1", 8888);
        try {
            client.resovleHarLog();
        } finally {
            client.shutdown();
        }
    }
}

猜你喜欢

转载自blog.51cto.com/dengshuangfu/2369768