Java Maven工程 gRPC demo

228 阅读4分钟

关于protobuf是什么?有什么用能干什么等相关的概述就不说明了

安装protobuf 编译器

github下载地址:Releases · protocolbuffers/protobuf (github.com)

官网:Protocol Buffers Documentation (protobuf.dev)

下载对应操作系统的安装包,配置protoc的环境变量。在终端输入如下命令查看protoc环境变量是否配置成功

// 如果输入此命令没有显示出对应的版本,说明环境变量配置错误
protoc --version

新建java maven工程

新建3个java maven工程,用来实现gRPC远程调用。

# 3个java maven 工程说明
rpc-grpc-api  # 此工程用来做共通工程,给服务端、客户端提供对应的proto文件生成的java代码
rpc-grpc-server # grpc的服务端,也可以说是服务的提供者
rpc-grpc-client # grpc的客户端

rpc-grpc-api

在此工程目录的src目录下新建一个proto目录,把所有编写的.proto文件存放到此目录。

新建Hello.proto文件

// protobuf的版本  
syntax = "proto3";  
  
// 是否生成多个文件  
option java_multiple_files = false;  
// 生成文件默认存放的包名  
option java_package = "com.grpc";  
// 生成proto对应的文件名  
option java_outer_classname = "HelloProto";  
  
// 定义消息,请求传递的参数  
message HelloRequest{  
string name = 1;  
}  
// 返回的消息  
message HelloResponse{  
string result = 1;  
}  
// 定义grpc服务  
service HelloGrpcService{  
rpc helloGrpc(HelloRequest) returns(HelloResponse);  
}

关于protobuf相关的语法查看官网。

// 使用protoc命令,把proto 文件中的IDL转换成对应的java编程语言
protoc --java_out=/xxx/xxx.proto

我们不使用这种方式,使用起来不太方便。在此使用的是grpc-java的maven插件来帮助我们快速的将proto文件内容生成对应的java代码

grpc-java github地址:grpc/grpc-java: The Java gRPC implementation. HTTP/2 based RPC (github.com)

在rpc-grpc-api的pom.xml文件中添加如下依赖:

<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-netty-shaded</artifactId>
  <version>1.51.0</version>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-protobuf</artifactId>
  <version>1.51.0</version>
</dependency>
<dependency>
  <groupId>io.grpc</groupId>
  <artifactId>grpc-stub</artifactId>
  <version>1.51.0</version>
</dependency>
<dependency> <!-- necessary for Java 9+ -->
  <groupId>org.apache.tomcat</groupId>
  <artifactId>annotations-api</artifactId>
  <version>6.0.53</version>
  <scope>provided</scope>
</dependency>

并在pom.xml的build标签中添加插件

<build>
  <extensions>
    <extension>
      <groupId>kr.motd.maven</groupId>
      <artifactId>os-maven-plugin</artifactId>
      <version>1.7.1</version>
    </extension>
  </extensions>
  <plugins>
    <plugin>
      <groupId>org.xolstice.maven.plugins</groupId>
      <artifactId>protobuf-maven-plugin</artifactId>
      <version>0.6.1</version>
      <configuration>
        <protocArtifact>com.google.protobuf:protoc:3.24.0:exe:${os.detected.classifier}</protocArtifact>
        <pluginId>grpc-java</pluginId>
        <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.60.0:exe:${os.detected.classifier}</pluginArtifact>
      </configuration>
      <executions>
        <execution>
          <goals>
            <goal>compile</goal>
            <goal>compile-custom</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>

注意:使用grpc-java插件,.proto文件必放置到proto目录中,否则使用此插件生成对应代码时会失败

打开idea中的maven菜单栏,进行如下图操作生成对应的java代码,此步骤只是将对应的.proto文件中定义的message转换成对应的java代码

image.png

生成的代码如下,还需将生成的代码拷贝到java目录下

image.png

然后等待上述文件生成成功后,再执行如下图操作,生成.proto文件中定义的service代码

image.png

同理,生成的代码还需要拷贝到java目录下

image.png

到此 rpc-grpc-api 工程的代码就生成完毕

rpc-grpc-server

在此rpc-grpc-server工程中的pom.xml文件中依赖rpc-grpc-api

<dependency>  
    <groupId>com.rpc</groupId>  
    <artifactId>rpc-grpc-api</artifactId>  
    <version>1.0-SNAPSHOT</version>  
</dependency>

新建一个HelloGrpcServiceImpl类继承rpc-grpc-api项目生成的HelloGrpcServiceGrpc.HelloGrpcServiceImplBase类,覆盖.proto文件中的helloGrpc方法,并书写对应的业务

public class HelloGrpcServiceImpl extends HelloGrpcServiceGrpc.HelloGrpcServiceImplBase {  
        @Override  
        public void helloGrpc(HelloProto.HelloRequest request, StreamObserver<HelloProto.HelloResponse> responseObserver) {  
            // 获取客户端传递的参数  
            String name = request.getName();  
            // 业务处理  
            System.out.println("获取到的参数为:" + name);  
            // 构建返回  
            HelloProto.HelloResponse.Builder responseBuilder = HelloProto.HelloResponse.newBuilder();  
            // 构建返回数据  
            responseBuilder.setResult("hello,I am grpc remote method result");  
            // 构建响应  
            HelloProto.HelloResponse response = responseBuilder.build();  

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

对应的rpc远程方法已经编写完毕,接下来编写一个main函数来模拟后端服务,代码如下:

public class Hello {  
        public static void main(String[] args) throws IOException, InterruptedException {  
            // 编写服务的构建者,并绑定端口  
            ServerBuilder serverBuilder = ServerBuilder.forPort(9000);  
            // 发布服务  
            serverBuilder.addService(new HelloGrpcServiceImpl());  
            // 创建服务  
            Server server = serverBuilder.build();  
            // 启动服务  
            server.start();  
            // 等待客户端的连接  
            server.awaitTermination();  

        }  
}

启动服务,检测是否错误,如果服务端没问题,接下来编写客户端

rpc-grpc-client

工程依赖rpc-grpc-api

<dependency>  
    <groupId>com.rpc</groupId>  
    <artifactId>rpc-grpc-api</artifactId>  
    <version>1.0-SNAPSHOT</version>  
</dependency>

然后在客户端工程新建main函数,模拟客户端调用rpc远程服务端,编写代码如下:

public class HelloClient {  
        public static void main(String[] args) {  
            // 创建连接服务端的通道  
            ManagedChannel managedChannel = ManagedChannelBuilder.forAddress("localhost",9000).usePlaintext().build();  
            // 获取代理对象stub  
            HelloGrpcServiceGrpc.HelloGrpcServiceBlockingStub helloGrpcService = HelloGrpcServiceGrpc.newBlockingStub(managedChannel);  
            // 准备远程调用参数  
            HelloProto.HelloRequest.Builder builder = HelloProto.HelloRequest.newBuilder();  
            builder.setName("hello grpc server,i am grpc client");  
            HelloProto.HelloRequest request = builder.build();  
            // 进行rpc远程调用  
            HelloProto.HelloResponse response = helloGrpcService.helloGrpc(request);  
            String result = response.getResult();  
            System.out.println("获取到rpc远程调用的结果为:"+result);  
        }  
}

启动客户端,观察调用结果,如果都正常,说明使用grpc进行远程调用ok

服务端调用输出内容:

image.png

客户端获取到的响应结果:

image.png

源代码地址:java-grpc-example: java 使用gRPC (gitee.com)