1. 程式人生 > >使用Grpc+maven定義接口、發布服務、調用服務

使用Grpc+maven定義接口、發布服務、調用服務

snapshot 接口 路徑 exception fin returns 對象 1.4.1 pri

項目使用maven構建,執行mvn compile 命令後,proto文件自動生成java文件,這個功能需要依賴相關編譯插件。
一、pom.xml配置

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.test.grpcTest</groupId>
  <artifactId>grpc-api</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>``
  <name>grpc-api</name>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
  <dependencies>
<!-- 添加grpc相關依賴包 -->      
    <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-netty</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-protobuf</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
            <groupId>io.grpc</groupId>
            <artifactId>grpc-stub</artifactId>
            <version>1.0.0</version>
        </dependency>
        <dependency>
                        <groupId>io.grpc</groupId>
                        <artifactId>grpc-all</artifactId>
                        <version>0.13.2</version>
                </dependency>
  </dependencies>
 <!-- proto自動生成java文件所需的編譯插件 -->  
  <build>
        <extensions>
            <extension>
                <groupId>kr.motd.maven</groupId>
                <artifactId>os-maven-plugin</artifactId>
                <version>1.4.1.Final</version>
            </extension>
        </extensions>
        <plugins>
            <plugin>
                <groupId>org.xolstice.maven.plugins</groupId>
                <artifactId>protobuf-maven-plugin</artifactId>
                <version>0.5.0</version>
                <configuration>                  <protocArtifact>com.google.protobuf:protoc:3.0.0:exe:${os.detected.classifier}</protocArtifact>
                    <pluginId>grpc-java</pluginId>
                    <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.0.0:exe:${os.detected.classifier}</pluginArtifact>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>compile</goal>
                            <goal>compile-custom</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

二、proto文檔(IDL文檔)編輯和編譯成java文件

//指定proto3格式
syntax = "proto3";
//一些生成代碼的設置
option java_multiple_files = false;//以非外部類模式生成
option java_package = "com.test.grpcTest.grpc_api";//所在包名
option java_outer_classname = "Grpc";//最外層類名稱
message UnaryRequest{
    string serviceName = 1;
    string methodName = 2;
    bytes data = 3;
    string request_id = 4;//參數默認都為可選,如果沒有賦值,那麽接口中不會出現該參數,不會默認為null之類的
}
message UnaryResponse{
    string serviceName = 1;
    string methodName = 2;
    bytes data = 3;
    string request_id = 4;
}
service GrpcService{
    // 一對一服務請求
    rpc SendUnaryRequest(UnaryRequest) returns(UnaryResponse);
}
proto文件編輯好後,在項目根目錄下執行 **mvn compile** 進行編譯 。
如果使用maven編譯proto文件,那麽需要默認將proto文件放在 /src/main/proto/  路徑下。
編譯後生成的java文件在 target/generated-sources/  路徑下。
將 java 文件拷貝到  /src/main/java/ 路徑下。
項目文件結構如下:

技術分享圖片

三、服務端代碼
在 /src/main/java/ 路徑下新建目錄 /server,存放服務端代碼。

package com.test.grpcTest.grpc_api.server;
import com.test.grpcTest.grpc_api.GrpcServiceGrpc;
import com.test.grpcTest.grpc_api.UnaryRequest;
import com.test.grpcTest.grpc_api.UnaryResponse;
import com.google.protobuf.ByteString;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import io.grpc.stub.StreamObserver;
import java.io.IOException;
//Grpc服務器對象
public class GrpcServer {
    private int port = 50051;//grpc服務端口
    private Server server;//grpc server
    public static void main(String[] args) throws IOException,InterruptedException {
        final GrpcServer server = new GrpcServer();
        server.start();
        server.blockUntilShutdown();
    }
    private void start() throws IOException {
        //指定grpc服務器端口、接口服務對象,啟動grpc服務器
        server = ServerBuilder.forPort(port).addService(new GreeterImpl())
            .build().start();
        System.out.println("service start...");
        //添加停機邏輯
        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.err.println("*** shutting down gRPC server since JVM is shutting down");
                GrpcServer.this.stop();
                System.err.println("*** server shut down");
            }
        });
    }
    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }
    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }
//內部類,繼承抽象類 GrpcServiceGrpc.GrpcServiceImplBase,
//並重寫服務方法 sendUnaryRequest
    private class GreeterImpl extends GrpcServiceGrpc.GrpcServiceImplBase {
//UnaryRequest 客戶端請求參數,
//StreamObserver<UnaryResponse> 返回給客戶端的封裝參數
        public void sendUnaryRequest(UnaryRequest request,StreamObserver<UnaryResponse> responseObserver) {
            ByteString message = request.getData();
            System.out.println("server, serviceName:" + request.getServiceName()
                + "; methodName:" + request.getMethodName()+"; datas:"+new String(message.toByteArray()));
            UnaryResponse.Builder builder = UnaryResponse.newBuilder();            builder.setServiceName("GrpcServiceResponse").setMethodName("sendUnaryResponse");
            responseObserver.onNext(builder.build());
            responseObserver.onCompleted();
        }
    }
}

服務端輸出日誌:
技術分享圖片

四、客戶端代碼

package com.test.grpcTest.grpc_api.client;
import java.util.concurrent.TimeUnit;
import com.test.grpcTest.grpc_api.GrpcServiceGrpc;
import com.test.grpcTest.grpc_api.UnaryRequest;
import com.test.grpcTest.grpc_api.UnaryResponse;
import com.google.protobuf.ByteString;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
//grpc客戶端類
public class GrpcClient {
    private final ManagedChannel channel;//客戶端與服務器的通信channel
    private final GrpcServiceGrpc.GrpcServiceBlockingStub blockStub;//阻塞式客戶端存根節點
    public GrpcClient(String host, int port) {
        channel = ManagedChannelBuilder.forAddress(host, port).usePlaintext(true).build();//指定grpc服務器地址和端口初始化通信channel
        blockStub = GrpcServiceGrpc.newBlockingStub(channel);//根據通信channel初始化客戶端存根節點
    }
    public void shutdown() throws InterruptedException{
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }
    //客戶端方法
    public void sayHello(String str){
        //封裝請求參數
        UnaryRequest request = UnaryRequest.newBuilder()            .setServiceName("GrpcServiceRequest").setMethodName("sendUnaryRequest").setData(ByteString.copyFrom(str.getBytes()))
            .build();
        //客戶端存根節點調用grpc服務接口,傳遞請求參數
        UnaryResponse response = blockStub.sendUnaryRequest(request);
        System.out.println("client, serviceName:"+response.getServiceName()+"; methodName:"+response.getMethodName());
    }
    public static void main(String[] args) throws InterruptedException{
        //初始化grpc客戶端對象
        GrpcClient client = new GrpcClient("127.0.0.1",50051);
        for(int i=0; i<5; i++){
            client.sayHello("client word:"+ i);
            Thread.sleep(3000);
        }
    }
}

客戶端輸出日誌:
技術分享圖片

使用Grpc+maven定義接口、發布服務、調用服務