文章目录

  • 1、实践
  • (1) IDEA安装插件
  • (2) 新建.proto文件
  • (3) pom引入依赖
  • (4) 生成代码
  • (5) 创建服务端
  • (6) 创建客户端
  • (7) 测试
  • 2、源码
  • (1) protobuf
  • (2) 重要类和接口


Java实现grpc

1、实践

(1) IDEA安装插件

Protobuf Support

Ceph java 源码 grpc java 源码_maven

(2) 新建.proto文件

我这里命名为test.proto。
指定生成代码的包路径、接口服务等。
定义了一个UserService服务,包含一个方法getUser()。以及请求类UserRequest、响应类UserReply。

syntax = "proto3";

option java_multiple_files = true;
option java_package = "io.grpc.examples";
option java_outer_classname = "UserProto";
option objc_class_prefix = "HLW";

package test;

// The user service definition.
service User {
    // getUser method
    rpc getUser (UserRequest) returns (UserReply) {}
}

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

// The response message containing the user
message UserReply {
    string message = 1;
}

(3) pom引入依赖

包括grpc、protobuf和protobuf插件。

<properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <protobuf.version>3.6.1</protobuf.version>
        <grpc.version>1.19.0</grpc.version>
    </properties>

    <dependencies>
     <dependency>
        <groupId>com.google.protobuf</groupId>
        <artifactId>protobuf-java</artifactId>
        <version>${protobuf.version}</version>
    </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</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>
    </dependencies>

    <build>
    <extensions>
        <extension>
            <groupId>kr.motd.maven</groupId>
            <artifactId>os-maven-plugin</artifactId>
            <version>1.5.0.Final</version>
        </extension>
    </extensions>
    <plugins>
        <!--protobuf插件-->
        <plugin>
            <groupId>org.xolstice.maven.plugins</groupId>
            <artifactId>protobuf-maven-plugin</artifactId>
            <version>0.5.0</version>
            <configuration>
                <!--
                  The version of protoc must match protobuf-java. If you don't depend on
                  protobuf-java directly, you will be transitively depending on the
                  protobuf-java version that grpc depends on.
                -->
                <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>
        </plugin>
    </plugins>
</build>

(4) 生成代码

操作protobuf插件的compile、compile-custom命令。

Ceph java 源码 grpc java 源码_rpc_02

生成的代码如下,包含:
● protoc-dependencies: 相关依赖,proto文件格式。
● protoc-plugins: pom中指定的插件。
● generated-sources: 生成的源码包文件。

(5) 创建服务端

Server端要提供一个查询服务,需要继承UserGrpc.UserImplBase。示例中,监听端口10001。
public class TestService extends UserGrpc.UserImplBase{

public void getUser(UserRequest request,
                        StreamObserver<UserReply> responseObserver) {
        UserReply reply = UserReply.newBuilder().setMessage("this is "+request.getName()).build();
        responseObserver.onNext(reply);
        responseObserver.onCompleted();
    }
}
public class UserServer {
    private Server server;

    public static void main(String[] args) throws InterruptedException, IOException {
        UserServer server=new UserServer();
        server.start();
        server.blockUntilShutdown();
    }
    private void start() throws IOException {
        int port=10001;
        server= ServerBuilder.forPort(port)
                .addService(new TestService())
                .build().start();
        System.out.println("server start..... listen on "+port);
        Runtime.getRuntime().addShutdownHook(new Thread(()->{
            System.out.println("shut down grpc server");
            try {
                UserServer.this.stop();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }));
    }

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

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

(6) 创建客户端

客户端这里要远程调用服务端的接口,因为是本地模拟,所以ip:127.0.0.1 port:10001。
通过Stub,像调用本地方法一样调用远程方法。

public class UserClient {
    private ManagedChannel channel;

    private UserGrpc.UserBlockingStub stub;

    public UserClient(String host,int port){
        channel= ManagedChannelBuilder.forAddress(host,port).usePlaintext().build();
        stub=UserGrpc.newBlockingStub(channel);
    }

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

    public String getUser(String name){
        UserRequest request = UserRequest.newBuilder().setName(name).build();
        UserReply helloReply = stub.getUser(request);
        return helloReply.getMessage();
    }

    public static void main(String[] args) throws InterruptedException {
        UserClient client=new UserClient("127.0.0.1",10001);
        String hello = client.getUser("hello");
        System.out.println("client:"+hello);
        client.shutdown();
    }
}

(7) 测试

因为我们是服务端监听客户端,所以要先启动服务端,再启动客户端。

Ceph java 源码 grpc java 源码_Ceph java 源码_03

2、源码

(1) protobuf

protocol buffers 是一种语言无关、平台无关、可扩展的序列化结构数据的方法,可用于数据通信协议和数据存储等,它是 Google 提供的一个具有高效协议数据交换格式工具库,是一种灵活、高效和自动化机制的结构数据序列化方法。

特点:二进制方式来表示数据。

相比XML,有编码后体积更小,编解码速度更快的优势;相比于 Json,Protobuf 有更高的转化效率,时间效率和空间效率都是 JSON 的 3-5 倍。

(2) 重要类和接口

针对上面生成的几个类和接口,做详细的说明:

Ceph java 源码 grpc java 源码_rpc_04

我们先介绍通过compile命令生成的java包下的类:

UserRequestOrBuilder:
用户服务的响应接口,getName()对应proto文件中的UserRequest的name字符串的get操作。

//proto
message UserRequest {
    string name = 1;
}
public interface UserRequestOrBuilder extends
    // @@protoc_insertion_point(interface_extends:test.UserRequest)
    com.google.protobuf.MessageOrBuilder {

  /**
   * <code>string name = 1;</code>
   */
  java.lang.String getName();
  /**
   * <code>string name = 1;</code>
   */
  com.google.protobuf.ByteString
      getNameBytes();
}

UserRequest:
封装的UserService的请求实体。
继承GeneratedMessageV3类,并实现UserRequestOrBuilder接口。
内部类Builder可以做参数处理,并对getName()的具体实现逻辑。

public  final class UserRequest extends
    com.google.protobuf.GeneratedMessageV3 implements
    // @@protoc_insertion_point(message_implements:test.UserRequest)
    UserRequestOrBuilder {
    
      public static final class Builder extends
      com.google.protobuf.GeneratedMessageV3.Builder<Builder> implements
      // @@protoc_insertion_point(builder_implements:test.UserRequest)
      io.grpc.examples.UserRequestOrBuilder {
             public Builder setName(java.lang.String value) {
                  if (value == null) {
                    throw new NullPointerException();
                  }
  
                  name_ = value;
                  onChanged();	
                  return this;
            }
            public java.lang.String getName() {
              java.lang.Object ref = name_;
              if (!(ref instanceof java.lang.String)) {
                com.google.protobuf.ByteString bs =(com.google.protobuf.ByteString) ref;
                java.lang.String s = bs.toStringUtf8();
                name_ = s;
                return s;
              } else {
                return (java.lang.String) ref;
              }
           }
      }
}

UserReplyOrBuilder:
用户服务的响应接口,getMessage()对应proto文件中的UserReply的message字符串的get操作。

//proto
message UserReply {
    string message = 1;
}
//UserReplyOrBuilder接口
public interface UserReplyOrBuilder extends
    // @@protoc_insertion_point(interface_extends:test.UserReply)
    com.google.protobuf.MessageOrBuilder {

  /**
   * <code>string message = 1;</code>
   */
  java.lang.String getMessage();
  /**
   * <code>string message = 1;</code>
   */
  com.google.protobuf.ByteString
      getMessageBytes();
}

UserResponse:
封装请求的响应实体。对getMessage()的具体实现。
与UserRequest类似,也有一个内部类Builder。

UserGrpc:
通过命令compile-custom生成。是grpc的核心类。
提供了三种场景的stub实现:UserStub(async)、UserBlockingStub(block)、UserFutureStub(ListenableFuture)

Ceph java 源码 grpc java 源码_rpc_05

下一篇介绍Nacos中的grpc应用。