原创

Java使用grpc利用protoc-gen-grpc-java生成protobuf

1. 介绍

  • grpc的适用于各种语言,且扩展性高
  • 以protobuf作为IDL,通过protoc来编译框架代码。gRPC的Java实现的底层网络库是基于Netty开发
  • 全网的教程都不全大部分都是只有中间部分,真是没有提到需要protoc-gen-grpc-java插件,所以我这篇应该是比较全的
  • 按照我的文章如果你跑不起来你的grpc应用 你都可以来打我
  • go,php,py,c艹等其他语言思路也都是和java一样的

2.安装

1.首先安装protoc程序

安装教程可以看 https://www.fireflyi.com/article/42

2.在安装protoc的插件protoc-gen-grpc-java

1.本地先安装gradle

  1. 去官网下载http://services.gradle.org/distributions/ 选个二进制zip下载
  2. 修改配置文件镜像仓库地址,不然一会编译的时候下载不到

去自己家目录 进去.gradle 目录 新建init.gradle然后写入,全局配置

allprojects{
    repositories {
        def ALIYUN_REPOSITORY_URL = 'http://maven.aliyun.com/nexus/content/groups/public'
        def ALIYUN_JCENTER_URL = 'http://maven.aliyun.com/nexus/content/repositories/jcenter'
        all { ArtifactRepository repo ->
            if(repo instanceof MavenArtifactRepository){
                def url = repo.url.toString()
                if (url.startsWith('https://repo1.maven.org/maven2')) {
                    project.logger.lifecycle "Repository ${repo.url} replaced by $ALIYUN_REPOSITORY_URL."
                    remove repo
                }
                if (url.startsWith('https://jcenter.bintray.com/')) {
                    project.logger.lifecycle "Repository ${repo.url} replaced by $ALIYUN_JCENTER_URL."
                    remove repo
                }
            }
        }
        maven {
            url ALIYUN_REPOSITORY_URL
            url ALIYUN_JCENTER_URL
        }
    }
}

如果只想修改当前项目的grable配置,直接修改项目下build.gradle文件即可

buildscript {
    repositories {
        maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
                maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
    }
    dependencies { classpath libraries.protobuf_plugin }
}

allprojects {
    repositories {
        maven { url 'http://maven.aliyun.com/nexus/content/groups/public/' }
        maven{ url 'http://maven.aliyun.com/nexus/content/repositories/jcenter'}
    }
}

2.编译安装protoc-gen-grpc-java

  1. 下载源码到本地 https://github.com/grpc/grpc-java
  2. 进入compiler目录执行命令~/Desktop/JDTool/gradle-5.5.1/bin/gradle java_pluginExecutable
ZBMAC-C02WD12BH:compiler lishihao$ ~/Desktop/JDTool/gradle-5.5.1/bin/gradle java_pluginExecutable

> Configure project :grpc-compiler
*** Building codegen requires Protobuf version 3.7.1
*** Please refer to https://github.com/grpc/grpc-java/blob/master/COMPILING.md#how-to-build-code-generation-plugin

> Configure project :grpc-gae-interop-testing-jdk8
Repository https://jcenter.bintray.com/ replaced by http://maven.aliyun.com/nexus/content/repositories/jcenter.

BUILD SUCCESSFUL in 1m 3s
2 actionable tasks: 2 executed

测试

ZBMAC-C02WD12BH:compiler lishihao$ ~/Desktop/JDTool/gradle-5.5.1/bin/gradle test
> Configure project :grpc-compiler
*** Building codegen requires Protobuf version 3.7.1
*** Please refer to https://github.com/grpc/grpc-java/blob/master/COMPILING.md#how-to-build-code-generation-plugin

> Configure project :grpc-gae-interop-testing-jdk8
Repository https://jcenter.bintray.com/ replaced by http://maven.aliyun.com/nexus/content/repositories/jcenter.

BUILD SUCCESSFUL in 56s
31 actionable tasks: 29 executed, 2 up-to-date

至此protoc和插件protoc-gen-grpc-java就安装成功可以使用了

3.使用protoc-gen-grpc-java生成java类文件

新建一个proto文件

syntax = "proto3";

option java_multiple_files = true;
option java_package = "com.grpc";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";

package helloworld;

// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply) {}
}

// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}

// The response message containing the greetings
message HelloReply {
  string message = 1;
}

在此文件目录下执行2个命令

  • 第一个命令是为了生成GreeterGrpc.java文件
  • 第二个命令是生成实体类信息

第一个命令A

ZBMAC-C02WD12BH:protobuf lishihao$ protoc --plugin=protoc-gen-grpc-java=/Users/lishihao/Desktop/github/grpc-java-master/compiler/build/exe/java_plugin/protoc-gen-grpc-java --grpc-java_out=./ --proto_path=./ helloworld.proto
  • --plugin=protoc-gen-grpc-java的值是刚刚安装的protoc-gen-grpc-java编译完成生成的插件目录
  • --grpc-java_out值为GreeterGrpc.java生成目录
  • --proto_path值为proto文件目录,记好mac下 ./后面需要加一个空格

第二个命令B

ZBMAC-C02WD12BH:protobuf lishihao$ protoc --java_out=./ helloworld.proto

最终生成的文件

至此gRPC的开发准备工作全部完成

3.开始gRPC的第一个程序

GrpcServer

public class GrpcServer {
    private static final Logger logger = Logger.getLogger(GrpcServer.class.getName());

    private Server server;

    private void start() throws IOException {
        /* The port on which the server should run */
        int port = 50051;
        server = ServerBuilder.forPort(port)
                .addService(new GreeterImpl())
                .build()
                .start();
        logger.info("Server started, listening on " + port);
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                // Use stderr here since the logger may have been reset by its JVM shutdown hook.
                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                GrpcServer.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }

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

    /**
     * Await termination on the main thread since the grpc library uses daemon threads.
     */
    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

    /**
     * Main launches the server from the command line.
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        final GrpcServer server = new GrpcServer();
        server.start();
        server.blockUntilShutdown();
    }

    static class GreeterImpl extends GreeterGrpc.GreeterImplBase {

        @Override
        public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) {
            HelloReply reply = HelloReply.newBuilder().setMessage("Hello111 " + req.getName()).build();
            responseObserver.onNext(reply);
            responseObserver.onCompleted();
        }
    }
}

GrpcClient

/**
 * @author by fireflyi (6025606@qq.com)
 * @website https://www.fireflyi.com
 * @date 2019/7/25
 * DESC TODO
 */
public class GrpcClient {
    private static final Logger logger = Logger.getLogger(GrpcClient.class.getName());

    private final ManagedChannel channel;
    private final GreeterGrpc.GreeterBlockingStub blockingStub;

    /** Construct client connecting to HelloWorld server at {@code host:port}. */
    public GrpcClient(String host, int port) {
        this(ManagedChannelBuilder.forAddress(host, port)
                // Channels are secure by default (via SSL/TLS). For the example we disable TLS to avoid
                // needing certificates.
                .usePlaintext(true)
                .build());
    }

    /** Construct client for accessing HelloWorld server using the existing channel. */
    GrpcClient(ManagedChannel channel) {
        this.channel = channel;
        blockingStub = GreeterGrpc.newBlockingStub(channel);
    }

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

    /** Say hello to server. */
    public void greet(String name) {
        logger.info("Will try to greet " + name + " ...");
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply response;
        try {
            response = blockingStub.sayHello(request);
        } catch (StatusRuntimeException e) {
            logger.log(Level.WARNING, "RPC failed: {0}", e.getStatus());
            return;
        }
        logger.info("Greeting: " + response.getMessage());
    }

    /**
     * Greet server. If provided, the first element of {@code args} is the name to use in the
     * greeting.
     */
    public static void main(String[] args) throws Exception {
        GrpcClient client = new GrpcClient("localhost", 50051);
        try {
            /* Access a service running on the local machine on port 50051 */
            String user = "world2222";
            if (args.length > 0) {
                user = args[0]; /* Use the arg as the name to greet if provided */
            }
            client.greet(user);
        } finally {
            client.shutdown();
        }
    }
}

测试

七月 25, 2019 8:04:58 下午 com.grpc.service.GrpcClient greet
信息: Will try to greet world2222 ...
七月 25, 2019 8:04:59 下午 com.grpc.service.GrpcClient greet
信息: Greeting: Hello111 world2222

4.总结

  • 按照上面步骤是可以完整的run起来
  • 如果出现protoc生成的java类有报错只有2种可能
    1. 使用的mvn依赖的版本和 syntax = "proto3"; protobug语法不一致
    2. 如果定义接口是单独的.proto文件,protoc需要对接口文件需要分别执行命令AB!!!
  • 源码地址 https://github.com/Fireflyi/xiaoqingxin/tree/master/grpc
正文到此结束
本文目录