springboot 集成GRPC,需要做如下准备
1. server端
2. client端
3. proto文件
4. 相应的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中写的数据