springboot 集成GRPC
springboot 集成GRPC,需要做如下准备
-
- server端
-
- client端
-
- proto文件
-
- 相应的pom
步骤1. 创建java maven工程
使用maven对Jar包进行管理,工程目录如下:
步骤2.在pom.xml中添加相应的依赖,
注意依赖的版本,不同的版本生成的代码可能不致,因为是示例demo,所以我把两个相应的包都放在了最外层的pom中,真正的项目中,两都是要分开在不同项目中,做到最小依赖;引入的POM并不是只有这一种方法,也可以单独引入sprintboot pom,再把grpc相关的引入,这些方式都可以,只是这个包里集成了这些,使用起来比较方便,线上项目可根据情况而定。
客户端的pom
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-client-spring-boot-starter</artifactId>
<version>2.2.1.RELEASE</version>
</dependency>
服务端pom
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>2.6.1.RELEASE</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>1.29.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>1.29.0</version>
</dependency>
步骤3. 编写proto文件
需要注意文件存放的位置。
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.sunrj.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)
<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.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>
步骤5. 生成GRPC代码
在idea中,使用ideal,直接在maven操作区,点击compile,如果出现错误,可能需要安装protobuf插件,点击compile之后,会在相应的目录生成代码,目录的设置是根据步骤4,以及proto的设置决定。
生成目录如下
步骤6.编写server端代码 ,需要引入api的pom
server端的目录结构
步骤 6.1 application.yaml
server:
port: 8081
spring:
application:
name: server
grpc:
server:
port: 8090
grpc.server.port 指的是grpc通信端口
spring.application.name 指的是server的项目名称,client访问时需要指定服务名称
server.port 指的是项目启动的端口
步骤6.2.编写启动类,标准启动类
@SpringBootApplication
public class GrpcServerApplication {
public static void main(String[] args) {
SpringApplication.run(GrpcServerApplication.class, args);
}
}
步骤6.3编写接收处理方法,UserInfoServiceGrpcImpl,
用于处理接收client 端GRPC的请求;该类直接继承UserInfoServiceGrpc.UserInfoServiceImplBase,实现其方法即可。由于是springboot 项目,类是交由spring进行管理,所以需要加上特定注解
@GrpcService
package come.koal.service;
import com.sunrj.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
client的目录结构
编写application.yml
server:
port: 8891
spring:
application:
name: client
grpc:
client:
grpc-server:
address: static://localhost:8090
enableKeepAlive: true
keepAliveWithoutCalls: true
negotiationType: plaintext
grpc.client.grpc-server 需要配置需要建的server的信息
启动类
@SpringBootApplication
public class GrpcClientApplication {
public static void main(String[] args) {
SpringApplication.run(GrpcClientApplication.class, args);
}
}
编写Controller,
这个controller就是rest请求的controller,用url调用,就是这个
@GrpcClient中的value值,就是server端的名称(spring.application.name )
package com.koal.controller;
import com.sunrj.grpc.userInfo.UserInfoServiceGrpc;
import com.sunrj.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;
}
}