springboot 集成 GRPC(https://so.csdn.net/so/search?q=GRPC&spm=1001.2101.3001.7020),需要做如下准备
server 端
client 端
proto 文件
相应的 pom
步骤 1.
创建 java maven 工程,使用 maven 对 Jar 包进行管理,工程目录如下:
步骤 2.
在 pom.xml 中添加相应的依赖,注意依赖的版本,不同的版本生成的代码可能不致,因为是示例 demo,所以我把两个相应的包都放在了最外层的 pom 中,真正的项目中,两都是要分开在不同项目中,做到最小依赖; 引入的 POM 并不是只有这一种方法,也可以单独引入 sprintboot pom,再把 grpc 相关的引入,这些方式都可以,只是这个包里集成了这些,使用起来比较方便,线上项目可根据情况而定。
<dependencies>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>2.10.1.RELEASE</version>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.10.1.RELEASE</version>
</dependency>
</dependencies>
步骤 3.
编写 proto 文件,我这里是在 api 中编写,跟 java 直接使用 grpc 一样,也需要注意文件存放的位置。
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.cc.grpc.userInfo";
service UserInfoService {
rpc queryUserInfo(UserInfoReq) returns (UserInfoResponse) {}
rpc queryUserInfo2(UserInfoReq) returns (UserInfoResponse) {}
rpc queryUserInfo3(UserStr) returns (UserStr) {}
}
message UserStr{
string str = 1;
}
message UserInfoReq {
string name = 1;
int64 id = 2;
}
message UserInfoResponse {
int32 code = 1;
string msg = 2;
bool success = 3;
message Data {
UserInfo userInfo = 1;
}
Data data = 4;
}
message UserInfo {
int64 id = 1;
string name = 2;
string sex = 3;
string addr = 4;
}
## 步骤 4.
在 api 的 pom.xml 中添加编译依赖,这里需要注意版本(protoc:3.12.0),其它的根据这个进行适配,这里没什么变化,java 直接使用 grpc 一致
<build>
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.6.2</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.12.0:exe:${os.detected.classifier}</protocArtifact>
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.34.1:exe:${os.detected.classifier}</pluginArtifact>
<!--设置grpc生成代码到指定路径-->
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<!--生成代码前是否清空目录-->
<clearOutputDirectory>false</clearOutputDirectory>
</configuration>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- 设置多个源文件夹 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.0.0</version>
<executions>
<!-- 添加主源码目录 -->
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${project.basedir}/src/main/gen</source>
<source>${project.basedir}/src/main/java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
## 步骤 5.
生成 GRPC 代码,使用 ideal,直接在 maven 操作区,点击 compile,如果出现错误,可能需要安装 protobuf 插件,点击 compile 之后,会在相应的目录生成代码,目录的设置是根据## 步骤 4,以及 proto 的设置决定。
步骤 6.
编写 server 端代码 ,需要引入 api 的 pom
步骤 6.1
编写 application.yml ,这里使用 bootstrap.yml 可能不生效,需要注意;
grpc.server.port 指的是 grpc 通信端口
spring.application.name 指的是 server 的项目名称,client 访问时需要指定服务名称
server.port 指的是项目启动的端口,如果不写,默认是 8080,我的 client 与 server 放在同一台机器,会发生冲突
grpc:
server:
port: 8888
spring:
application:
name: grpc-server
server:
port: 8890
步骤 6.2.
编写启动类,标准启动类
## 步骤 6.3
编写接收处理方法,UserInfoServiceGrpcImpl,用于处理接收 client 端 GRPC 的请求;该类直接继承 UserInfoServiceGrpc.UserInfoServiceImplBase,实现其方法即可。由于是 springboot 项目,类是交由 spring 进行管理,所以需要加上特定注解 @GrpcService
package com.cc.grpc.server.service;
import com.cc.grpc.userInfo.*;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class UserInfoServiceGrpcImpl extends UserInfoServiceGrpc.UserInfoServiceImplBase {
@Override
public void queryUserInfo(UserInfoReq request, io.grpc.stub.StreamObserver<UserInfoResponse> responseObserver) {
UserInfoResponse.Builder userInfoResp = UserInfoResponse.newBuilder();
userInfoResp.setCode(0).setMsg("success").setSuccess(true);
UserInfo.Builder userInfo = UserInfo.newBuilder();
userInfo.setId(request.getId());
userInfo.setName(request.getName());
userInfoResp.setData(UserInfoResponse.Data.newBuilder().setUserInfo(userInfo));
responseObserver.onNext(userInfoResp.build());
responseObserver.onCompleted();
}
@Override
public void queryUserInfo2(UserInfoReq request, io.grpc.stub.StreamObserver<UserInfoResponse> responseObserver) {
super.queryUserInfo2(request, responseObserver);
}
@Override
public void queryUserInfo3(UserStr request, io.grpc.stub.StreamObserver<UserStr> responseObserver) {
System.out.println("queryUserInfo3 =======> " + request.getStr());
responseObserver.onNext(UserStr.newBuilder().setStr("msg : success").build());
responseObserver.onCompleted();
}
}
步骤 7
编写 client 端代码,需要引入 api 的 pom
## 步骤 7.1
编写 application.yml
grpc.client.grpc-server 需要配置需要建的 server 的信息
address 为必需,由于我这里是 demo,所以写了静态 IP
grpc:
client:
grpc-server:
address: static://localhost:8888
enableKeepAlive: true
keepAliveWithoutCalls: true
negotiationType: plaintext
spring:
application:
name: grpc-client
server:
port: 8891
## 步骤 7.2
编写启动类,也是标准代码
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
步骤 7.3
编写 Controller,这个 controller 就是 rest 请求的 controller,用 url 调用,就是这个
@GrpcClient 中的 value 值,就是 server 端的名称(spring.application.name )
import com.cc.grpc.userInfo.UserInfoServiceGrpc;
import com.cc.grpc.userInfo.UserStr;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.concurrent.ExecutionException;
@RestController
@RequestMapping("/userInfo")
public class UserInfoController {
@GrpcClient("grpc-server")
UserInfoServiceGrpc.UserInfoServiceFutureStub userInfoServiceStub;
@RequestMapping(value="/query/{id}")
public String queryUser(@PathVariable Integer id, String str) {
String userResp = null;
try {
userResp = userInfoServiceStub.queryUserInfo3(UserStr.newBuilder().setStr(str).build()).get().getStr();
return userResp;
} catch (InterruptedException e) {
} catch (ExecutionException e) {
}
return userResp;
}
}
测试
返回的值就是 server 中写的数据
作者:llyilo
来源链接:
https://blog.csdn.net/llyilo/article/details/122554816