gRPC构建RPC服务

本文介绍如何使用Grpc来否件和发布RPC服务,本文在最后附上github地址。

1.下载&安装 java版本的protoc,下载地址

我这里使用的是3.3.0版本,如图所示


gRPC构建RPC服务_第1张图片
protoc-version.png

选择一个属于你的平台protoc来安装,安装很简单,只需要将下载好的protoc的zip包解压到指定目录即可。

2.创建maven工程

选择一款你喜欢的编译器创建一个maven工程,maven工程创建好之后,在其工程的根目录下的pom文件中添加如下内容:

pom.xml文件内容:


    1.6.1
    1.8
    3.3.0
    1.5.0.Final



      
       
           io.grpc
           grpc-netty
           ${grpc.version}
       
       
           io.grpc
           grpc-protobuf
           ${grpc.version}
       
       
           io.grpc
           grpc-stub
           ${grpc.version}
       



       
           
               kr.motd.maven
               os-maven-plugin
               ${kr.motd.version}
           
       

       
           
           
               org.xolstice.maven.plugins
               protobuf-maven-plugin
               0.5.0
               
               
                   com.google.protobuf:protoc:${protoc.version}:exe:${os.detected.classifier}
                   grpc-java
                   io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}
                   
                   
                   src/main/proto
                   
                   /Volumes/NETAC/soft/dev/protoc/bin/protoc
               
               
                   
                       
                           compile
                           compile-custom
                       
                   
               
           

           
           
               org.apache.maven.plugins
               maven-compiler-plugin
               
                   ${jdk.version}
                   ${jdk.version}
               
           
       

3.创建proto规则文件

在工程目录下的src/main下创建proto规则文件目录,目录结构如图所示:
gRPC构建RPC服务_第2张图片
proto_dir.png

3.1.创建规则文件

在这里我的proto规则文件中分别定义了Account和Greeter两个服务接口。

  • Greeter服务接口中定义了SayHello一个方法。
    在Greeter服务中的方法只是简单的打招呼方法。

  • Account服务接口中定义了addAccount和getAccoutByName两个方法。
    在Account服务中的这两个方法功能是模拟添加和查询账户。

3.1.1.定义服务

在创建好的proto目录下创建hello_account.proto规则文件,用于定义rpc服务,内容如下:

//使用proto3语法
syntax = "proto3";

//指定proto文件包名
package org.cooze.grpc.service;

//指定 java 包名
option java_package = "org.cooze.grpc.service";
//指定proto文件生成java文件后的类名
option java_outer_classname = "ServiceProto";

//开启多文件
option java_multiple_files = true;

//倒入指定的.proto文件
import "entity/req_res.proto";

//定义rpc服务接口
service Greeter {
  //服务端接口方法
  rpc SayHello (org.cooze.grpc.entity.HelloRequest) returns (org.cooze.grpc.entity.HelloReply);
}

//定义rpc服务接口
service Account {
   rpc addAccount(org.cooze.grpc.entity.Account) returns (org.cooze.grpc.entity.AccountResponse);
   rpc getAccoutByName(org.cooze.grpc.entity.Account) returns (org.cooze.grpc.entity.AccountResponse);
}

3.1.2.定义消息

在proto目录下的子目录entity中创建req_res.proto文件,用于定义rpc的消息类型,内容如下:

//使用proto3语法
syntax = "proto3";

//指定proto文件包名
package org.cooze.grpc.entity;

//指定 java 包名
option java_package = "org.cooze.grpc.entity";
//指定proto文件生成java文件后的类名
option java_outer_classname = "EntityProto";

//开启多文件
option java_multiple_files = true;

//请求参数
message HelloRequest {
  string name = 1;
}

//响应参数
message HelloReply {
  string message = 1;
}

message Account {
    string name = 1;
    string sex = 2;
    int32 age = 3;
}

message AccountResponse {
    string msg = 1;
    int32 code = 2;
    repeated Account results = 3;
}

proto3定义服务和消息,请参看我翻译的《gRPC之proto语法》,翻译难免带有个人主观色彩,请见谅.

3.2.编译proto文件

在创建好proto文件,并定义好消息类型和服务之后,结下来就是编译proto规则文件生成对应的java代码。

打开命令终端并切换到工程根目录下
我这里使用的编译器是idea编译器,所以打开终端很简单-_-!,终端打开后键入命令mvn compile编译即可,如图 :

gRPC构建RPC服务_第3张图片
compile.png

在执行完比那一命令之后,在工程根目录下会生成的target,而target目录的结构以及java类文件,如下图所示:


gRPC构建RPC服务_第4张图片
generator_code.png

其中,生成的服务定义接口类为:AccountGrpc和GreeterGrpc,消息类型类为:Account、AccountResponse、HelloReply、HelloRequest

4.Grpc服务和客户端实现

完成编辑proto规则文件和生成对应待grpc代码之后,就可以开始实现Grpc的服务端代码和客户端代码了。
创建java包结构和文件,如图所示:


gRPC构建RPC服务_第5张图片
create_package.png

4.1.Grpc服务端业务实现代码

不多说啥了,代码里有注释,所以上代码!

GreeterImpl.java代码如下:

public class GreeterImpl extends GreeterGrpc.GreeterImplBase {

    @Override
    public void sayHello(HelloRequest req, StreamObserver responseObserver) {
        HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + req.getName()).build();

        //处理接收到的消息
        String msg = reply.getMessage();
        System.out.println("服务端收到消息:" + msg);

        //响应消息
        HelloReply response = reply.toBuilder().setMessage("世界你好!").build();

        responseObserver.onNext(response);
        responseObserver.onCompleted();

    }
}

AccountImpl.java代码如下:

public class AccountImpl extends AccountGrpc.AccountImplBase {

    @Override
    public void addAccount(Account request, StreamObserver responseObserver) {
        //处理请求参数
        System.out.println(StringFormatter.format("新增用户:%s\n性别:%s\n年龄:%d岁", request.getName(), request.getSex(), request.getAge()).get());

        //处理响应参数
        AccountResponse response = AccountResponse.getDefaultInstance().toBuilder()
                .setCode(10000)
                .setMsg("success!").build();
        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }

    @Override
    public void getAccoutByName(Account request, StreamObserver responseObserver) {
        //处理请求参数
        System.out.println(StringFormatter.format("请求查询用户名:%s", request.getName()).get());

        //处理响应参数
        List list = new ArrayList<>();
        Account account1 = Account.getDefaultInstance().toBuilder()
                .setName("张三")
                .setAge(20)
                .setSex("男").build();
        list.add(account1);

        Account account2 = Account.getDefaultInstance().toBuilder()
                .setAge(30)
                .setSex("男")
                .setName("李四").build();

        list.add(account2);

        AccountResponse response = AccountResponse.getDefaultInstance().toBuilder()
                .setCode(10000)
                .setMsg("success!")
                .addAllResults(list)
                .build();

        responseObserver.onNext(response);
        responseObserver.onCompleted();
    }
}

4.2.Grpc客户端代码

不多说啥了,代码里有注释,所以上代码!

BaseClient.java代码如下:

public class BaseClient {

    private final ManagedChannel channel;
    private final GreeterGrpc.GreeterBlockingStub greeterBlockingStub;
    private final AccountGrpc.AccountBlockingStub accountBlockingStub;

    private BaseClient(ManagedChannel channel) {
        this.channel = channel;
        this.greeterBlockingStub = GreeterGrpc.newBlockingStub(channel);
        this.accountBlockingStub = AccountGrpc.newBlockingStub(channel);
    }

    /**
     * 构造客户端与Greeter 服务端连接 {@code host:port}
     *
     * @param host 主机地址
     * @param port 端口
     */
    public BaseClient(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());
    }

    /**
     * 关闭函数
     * @throws InterruptedException
     */
    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
    }

    public GreeterGrpc.GreeterBlockingStub getGreeterBlockingStub() {
        return greeterBlockingStub;
    }

    public AccountGrpc.AccountBlockingStub getAccountBlockingStub() {
        return accountBlockingStub;
    }
}

GreeterClient.java代码如下:

public class GreeterClient {

    private final GreeterGrpc.GreeterBlockingStub blockingStub;


    public GreeterClient(BaseClient client) {
        blockingStub = client.getGreeterBlockingStub();
    }

    public void greet(String name) {
        HelloRequest request = HelloRequest.newBuilder().setName(name).build();
        HelloReply response;
        try {
            response = blockingStub.sayHello(request);
            String msg = response.getMessage();
            //接收到服务端返回的消息
            System.out.println("客户端收到消息:" + msg);
        } catch (StatusRuntimeException e) {
            return;
        }
    }
}

AccountClient.java代码如下:

public class AccountClient {

    private final AccountGrpc.AccountBlockingStub accountBlockingStub;

    private final BaseClient client;

    public AccountClient(BaseClient client) {
        this.client = client;
        this.accountBlockingStub = client.getAccountBlockingStub();
    }

    public void addAccount(String name, String sex, int age) {

        Account account = Account.getDefaultInstance().toBuilder()
                .setName(name)
                .setSex(sex)
                .setAge(age)
                .build();

        AccountResponse response = this.accountBlockingStub.addAccount(account);

        System.out.println(StringFormatter.format("返回消息:%s\n状态:%d", response.getMsg(), response.getCode()).get());
    }

    public void queryAccout(String name) {
        Account account = Account.getDefaultInstance().toBuilder()
                .setName(name).build();
        AccountResponse response = this.accountBlockingStub.getAccoutByName(account);

        System.out.println(StringFormatter.format("返回消息:%s\n状态:%d", response.getMsg(), response.getCode()).getValue());
        System.out.println("查询结果:");
        List list = response.getResultsList();
        for (Account acc : list) {
            System.out.println(StringFormatter.format("姓名:%s,性别:%s,年龄:%d", acc.getName(), acc.getSex(), acc.getAge()).get());
        }
    }
}

4.3.Grpc服务端启动引导类代码

不多说啥了,代码里有注释,所以上代码!

rpc引导类BootStrap.java代码如下:

public class BootStrap {

    private Server server;

    /**
     * 服务启动类
     *
     * @param port 端口
     * @throws IOException
     */
    private void start(int port) throws IOException {
        server = ServerBuilder.forPort(port)
                //注册服务
                .addService(new GreeterImpl())
                .addService(new AccountImpl())
                .build()
                .start();

        Runtime.getRuntime().addShutdownHook(new Thread() {
            @Override
            public void run() {
                System.err.println("*** JVM 关闭,导致gRPC服务关闭!");
                BootStrap.this.stop();
                System.err.println("*** 服务关闭");
            }
        });
    }

    /**
     * RPC 服务关闭
     */
    private void stop() {
        if (server != null) {
            server.shutdown();
        }
    }

    /**
     * 设置守护进程
     */
    private void blockUntilShutdown() throws InterruptedException {
        if (server != null) {
            server.awaitTermination();
        }
    }

    /**
     * RPC服务启动main函数
     */
    public static void main(String[] args) throws IOException, InterruptedException {
        final BootStrap server = new BootStrap();
        server.start(50051);
        server.blockUntilShutdown();
    }
}

4.3.Grpc测试

测试类代码如下:

public class Test {
    public static void main(String[] args) throws Exception {

        BaseClient client = new BaseClient("localhost", 50051);
        try {
            System.out.println("===============GreeterClient============");
            GreeterClient greeterClient = new GreeterClient(client);
            greeterClient.greet("Hello");

            System.out.println("===============AccountClient============");
            AccountClient accountClient = new AccountClient(client);

            System.out.println("===============新增============");
            accountClient.addAccount("张飞", "男", 45);

            System.out.println("===============查找============");
            accountClient.queryAccout("测试");


        } finally {
            client.shutdown();
        }
    }

}

好了,所有的前序工作都做完了,开始测试了!

  • 启动rpc引导类BootStrap.java
  • 运行客户端测试类

服务端效果图如下:


gRPC构建RPC服务_第6张图片
server.png

客户端效果图如下:


gRPC构建RPC服务_第7张图片
client.png



打完收工,项目代码地址

你可能感兴趣的:(gRPC构建RPC服务)