模式:普通模式 客户端流 服务端流 双端流
客户端:普通阻塞客户端 完全异步客户端(出入参都是异步) 可阻塞可异步客户端(get,addListener)
客户端请求示例:
package com.aniu.inspection.api.controller;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.util.JsonFormat;
import com.google.protobuf.util.JsonFormat.Printer;
import com.aniu.inspection.grpc.*;
import io.grpc.stub.StreamObserver;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.client.inject.GrpcClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CountDownLatch;
/**
* @author pengyouy
* @since 2022/7/4
* 四种模式 三个客户端
* 普通模式 客户端流 服务端流 双端流
* 普通阻塞客户端 完全异步客户端(出入参都是异步) 可阻塞可异步客户端(get,addListener)
*/
@RestController
@RequestMapping("test")
@Slf4j
public class HelloController {
private final Printer printer = JsonFormat.printer().omittingInsignificantWhitespace();
/**
* 普通阻塞客户端
*/
@GrpcClient("inspection-service")
private ModuleTestGrpc.ModuleTestBlockingStub moduleTestBlockingStub;
/**
* 完全的异步客户端
*/
@GrpcClient("inspection-service")
private ModuleTestGrpc.ModuleTestStub moduleTestStub;
/**
* 可以异步可以同步的客户端
* get 阻塞Future
* addListener 异步
*/
@GrpcClient("inspection-service")
private ModuleTestGrpc.ModuleTestFutureStub moduleTestFutureStub;
/**
* 双端流
* 客户端多次发送
* 服务端多次返回
* 异步客户端+双端流模式
*
* @return
* @throws InterruptedException
*/
@GetMapping("doubleModule")
public List doubleModule() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
ArrayList<Object> objects = new ArrayList<>(16);
StreamObserver<InspectionPlanListByMasterDTO> inspectionPlanListByMasterDTOStreamObserver = moduleTestStub.inspectionPlanListByMasterIdAndServerStream(new StreamObserver<InspectionPlanByMasterDTO>() {
@SneakyThrows
@Override
public void onNext(InspectionPlanByMasterDTO value) {
String print = printer.print(value);
log.info("[收到服务端发来] : " + print);
objects.add(print);
}
@Override
public void onError(Throwable t) {
log.error(t.getMessage(), t);
countDownLatch.countDown();
}
@Override
public void onCompleted() {
log.debug("服务端 onCompleted");
countDownLatch.countDown();
}
});
for (Integer integer : Arrays.asList(1, 2)) {
inspectionPlanListByMasterDTOStreamObserver.onNext(InspectionPlanListByMasterDTO.newBuilder().setMasterPlanId(integer + "").build());
}
inspectionPlanListByMasterDTOStreamObserver.onCompleted();
countDownLatch.await();
return objects;
}
/**
* 客户端流
* 客户端多次发送
* 服务端一次返回
* 异步客户端+客户端流模式
* 阻塞http请求知道服务端返回
*
* @return
* @throws InterruptedException
*/
@GetMapping("clientModule")
public List clientModule() throws InterruptedException {
ArrayList<Object> objects = new ArrayList<>(16);
CountDownLatch countDownLatch = new CountDownLatch(1);
StreamObserver<InspectionPlanListByMasterDTO> inspectionPlanListByMasterDTOStreamObserver = moduleTestStub.inspectionPlanListByMasterIdAndOnlyClientStream(new StreamObserver<InspectionPlanListByMasterResponse>() {
@SneakyThrows
@Override
public void onNext(InspectionPlanListByMasterResponse value) {
log.info("[收到服务端发来] : " + value);
objects.add(printer.print(value));
}
@SneakyThrows
@Override
public void onError(Throwable t) {
log.error(t.getMessage(), t);
countDownLatch.countDown();
}
@Override
public void onCompleted() {
log.info("服务端 onCompleted");
countDownLatch.countDown();
}
});
for (Integer integer : Arrays.asList(1, 2)) {
inspectionPlanListByMasterDTOStreamObserver.onNext(InspectionPlanListByMasterDTO.newBuilder().setMasterPlanId(integer + "").build());
}
inspectionPlanListByMasterDTOStreamObserver.onCompleted();
countDownLatch.await();
return objects;
}
/**
* 服务端流
* 客户端一次发送
* 服务端多次返回
* 异步客户端+服务端流模式
*
* @return
* @throws InterruptedException
*/
@GetMapping("serverModule")
public List serverModule() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1);
ArrayList<Object> objects = new ArrayList<>(16);
List<Integer> integers = Arrays.asList(1, 2);
for (int i = 0; i < integers.size(); i++) {
InspectionPlanListByMasterDTO.Builder builder = InspectionPlanListByMasterDTO.newBuilder();
builder.setMasterPlanId(i + "");
moduleTestStub.inspectionPlanListByMasterIdAndOnlyServerStream(builder.build(), new StreamObserver<InspectionPlanByMasterDTO>() {
@SneakyThrows
@Override
public void onNext(InspectionPlanByMasterDTO value) {
log.info("[收到服务端发来] : " + value);
objects.add(printer.print(value));
}
@Override
public void onError(Throwable t) {
log.error(t.getMessage(), t);
countDownLatch.countDown();
}
@Override
public void onCompleted() {
log.info("服务端 onCompleted");
countDownLatch.countDown();
}
});
}
countDownLatch.await();
return objects;
}
/**
* 普通模式
* 客户端一次发送
* 服务端一次返回
* 多个就循环
* 异步客户端+普通调用模式
*
* @return
* @throws InterruptedException
*/
@GetMapping("ordinaryModule")
public List ordinaryModule() throws InterruptedException {
ArrayList<Object> objects = new ArrayList<>(16);
List<Integer> integers = Arrays.asList(1, 2);
for (int i = 0; i < integers.size(); i++) {
InspectionPlanListByMasterDTO.Builder builder = InspectionPlanListByMasterDTO.newBuilder();
builder.setMasterPlanId(i + "");
moduleTestStub.inspectionPlanListByMasterId(builder.build(), new StreamObserver<InspectionPlanListByMasterResponse>() {
@SneakyThrows
@Override
public void onNext(InspectionPlanListByMasterResponse value) {
log.info("[收到服务端发来] : " + value);
objects.add(printer.print(value));
}
@Override
public void onError(Throwable t) {
log.error(t.getMessage(), t);
}
@Override
public void onCompleted() {
log.info("服务端 onCompleted");
}
});
}
return objects;
}
/**
* 普通阻塞客户端+普通调用模式
*
* @return
* @throws InterruptedException
* @throws InvalidProtocolBufferException
*/
@GetMapping("ordinaryModuleBlock")
public List ordinaryModuleBlock() throws InterruptedException, InvalidProtocolBufferException {
ArrayList<Object> objects = new ArrayList<>(16);
List<Integer> integers = Arrays.asList(1, 2);
for (int i = 0; i < integers.size(); i++) {
InspectionPlanListByMasterDTO.Builder builder = InspectionPlanListByMasterDTO.newBuilder();
builder.setMasterPlanId(i + "");
InspectionPlanListByMasterResponse inspectionPlanListByMasterResponse = moduleTestBlockingStub.inspectionPlanListByMasterId(builder.build());
String print = printer.print(inspectionPlanListByMasterResponse);
objects.add(print);
}
return objects;
}
}
服务端代码实例:
package com.aniu.inspection.grpc.server;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.aniu.inspection.grpc.InspectionPlanByMasterDTO;
import com.aniu.inspection.grpc.InspectionPlanListByMasterDTO;
import com.aniu.inspection.grpc.InspectionPlanListByMasterResponse;
import com.aniu.inspection.grpc.ModuleTestGrpc;
import com.aniu.inspection.model.entity.InspectionPlan;
import com.aniu.inspection.model.entity.InspectionPlanRelation;
import com.aniu.inspection.service.IInspectionPlanRelationService;
import com.aniu.inspection.service.IInspectionPlanService;
import io.grpc.stub.StreamObserver;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import net.devh.boot.grpc.server.service.GrpcService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/**
* @author pengyouy
* @since 2022/7/7
* grpc 模式示例
*/
@GrpcService
@Slf4j
public class ModuleTestGrpcImpl extends ModuleTestGrpc.ModuleTestImplBase {
@Autowired
private IInspectionPlanRelationService inspectionPlanRelationService;
@Autowired
private IInspectionPlanService inspectionPlanService;
@Override
@Transactional(readOnly = true)
public void inspectionPlanListByMasterId(InspectionPlanListByMasterDTO request, StreamObserver<InspectionPlanListByMasterResponse> responseObserver) {
InspectionPlanListByMasterResponse.Builder builder = InspectionPlanListByMasterResponse.newBuilder();
Set<String> planIdList = Optional.of(inspectionPlanRelationService.list(
Wrappers.<InspectionPlanRelation>lambdaQuery()
.select(InspectionPlanRelation::getPlanId)
.eq(InspectionPlanRelation::getMasterPlanId, request.getMasterPlanId()))
.stream().map(InspectionPlanRelation::getPlanId).collect(Collectors.toSet()))
// 构造一个不存在的id值防止in()
.filter(f -> f.size() > 0)
.orElseGet(() -> Collections.singleton(UUID.randomUUID().toString()));
List<InspectionPlanListByMasterResponse.InspectionPlanList> collect = inspectionPlanService.list(
Wrappers.<InspectionPlan>lambdaQuery()
.orderByDesc(InspectionPlan::getSysCreated)
.in(InspectionPlan::getId, planIdList))
.stream().map(f ->
InspectionPlanListByMasterResponse.InspectionPlanList.newBuilder()
.setPlanId(f.getId())
.setDepartmentId(f.getDepartmentId())
.setName(f.getName())
.setNumber(f.getNumber())
.setYear(f.getYear()).build()).collect(Collectors.toList());
for (int i = 0; i < collect.size(); i++) {
builder.addList(i, collect.get(i));
}
responseObserver.onNext(builder.build());
responseObserver.onCompleted();
}
@Override
public void inspectionPlanListByMasterIdAndOnlyServerStream(InspectionPlanListByMasterDTO request, StreamObserver<InspectionPlanByMasterDTO> responseObserver) {
// 查询主计划和计划的所有关系
Optional.of(inspectionPlanRelationService.list(Wrappers.<InspectionPlanRelation>lambdaQuery()
.eq(InspectionPlanRelation::getMasterPlanId, request.getMasterPlanId())))
.filter(f -> f.size() > 0)
.map(m -> inspectionPlanService.list(Wrappers.<InspectionPlan>lambdaQuery()
.in(InspectionPlan::getId,
m.stream().map(InspectionPlanRelation::getPlanId).collect(Collectors.toSet()))))
.ifPresent(i -> i.forEach(f -> responseObserver.onNext(InspectionPlanByMasterDTO.newBuilder()
.setPlanId(f.getId())
.setDepartmentId(f.getDepartmentId())
.setName(f.getName())
.setNumber(f.getNumber())
.setYear(f.getYear()).build())));
responseObserver.onCompleted();
}
@Override
public StreamObserver<InspectionPlanListByMasterDTO> inspectionPlanListByMasterIdAndOnlyClientStream(StreamObserver<InspectionPlanListByMasterResponse> responseObserver) {
return new StreamObserver<InspectionPlanListByMasterDTO>() {
final List<InspectionPlan> inspectionPlans = new CopyOnWriteArrayList<>();
@SneakyThrows
@Override
public void onNext(InspectionPlanListByMasterDTO value) {
log.info("[收到客户端消息]: " + value);
// 查询主计划和计划的所有关系
Optional.of(inspectionPlanRelationService.list(Wrappers.<InspectionPlanRelation>lambdaQuery()
.eq(InspectionPlanRelation::getMasterPlanId, value.getMasterPlanId())))
.filter(f -> f.size() > 0)
.map(m -> inspectionPlanService.list(Wrappers.<InspectionPlan>lambdaQuery()
.in(InspectionPlan::getId,
m.stream().map(InspectionPlanRelation::getPlanId).collect(Collectors.toSet()))))
.ifPresent(inspectionPlans::addAll);
}
@Override
public void onError(Throwable t) {
log.error(t.getMessage(), t);
}
@SneakyThrows
@Override
public void onCompleted() {
log.debug("客户端调用参数onCompleted");
InspectionPlanListByMasterResponse.Builder builder = InspectionPlanListByMasterResponse.newBuilder();
List<InspectionPlanListByMasterResponse.InspectionPlanList> collect = inspectionPlans.stream().map(f -> InspectionPlanListByMasterResponse.InspectionPlanList.newBuilder()
.setPlanId(f.getId())
.setDepartmentId(f.getDepartmentId())
.setName(f.getName())
.setNumber(f.getNumber())
.setYear(f.getYear()).build()).collect(Collectors.toList());
builder.addAllList(collect);
InspectionPlanListByMasterResponse build = builder.build();
responseObserver.onNext(build);
responseObserver.onCompleted();
}
};
}
@Override
public StreamObserver<InspectionPlanListByMasterDTO> inspectionPlanListByMasterIdAndServerStream(StreamObserver<InspectionPlanByMasterDTO> responseObserver) {
return new StreamObserver<InspectionPlanListByMasterDTO>() {
@Override
public void onNext(InspectionPlanListByMasterDTO value) {
log.info("[收到客户端消息]: " + value);
// 查询主计划和计划的所有关系
Optional.of(inspectionPlanRelationService.list(Wrappers.<InspectionPlanRelation>lambdaQuery()
.eq(InspectionPlanRelation::getMasterPlanId, value.getMasterPlanId())))
.filter(f -> f.size() > 0)
.map(m -> inspectionPlanService.list(Wrappers.<InspectionPlan>lambdaQuery()
.in(InspectionPlan::getId,
m.stream().map(InspectionPlanRelation::getPlanId).collect(Collectors.toSet()))))
.ifPresent(i -> i.forEach(f -> responseObserver.onNext(InspectionPlanByMasterDTO.newBuilder()
.setPlanId(f.getId())
.setDepartmentId(f.getDepartmentId())
.setName(f.getName())
.setNumber(f.getNumber())
.setYear(f.getYear()).build())));
}
@Override
public void onError(Throwable t) {
}
@Override
public void onCompleted() {
log.debug("客户端调用参数onCompleted");
responseObserver.onCompleted();
}
};
}
}
服务端流日志traceId以及装饰类
装饰类:
package com.aniu.inspection.grpc.extension;
import cn.hutool.core.util.StrUtil;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.util.JsonFormat;
import io.grpc.stub.StreamObserver;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
import org.joda.time.Interval;
import org.slf4j.MDC;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* @author pengyouy
* @since 2022/7/6
* 自定义包装类 用来获取响应参数配合aop打印出参数以及时间
*/
@Slf4j
public class StreamObserverWrapper<v extends Message> implements StreamObserver<v> {
private static final int ADJ_LEN = 4096;
private static final String KEY_TRACE_ID = "requestId";
/**
* message json打印对象
*/
private final static JsonFormat.Printer PRINTER = JsonFormat.printer().omittingInsignificantWhitespace();
/**
* 被装饰的原对象
*/
private final StreamObserver<v> own;
/**
* 包装保存onNext参数
* 参数json数据
* 多次调用使用集合
*/
private final List<String> nextValueList = new CopyOnWriteArrayList<String>();
/**
* 初始化时间
*/
private final DateTime initTime;
/**
* 调用onCompleted 时间
*/
private DateTime onCompletedTime;
/**
* 请求json参数
*/
private final List<String> carryJsonParamList = new CopyOnWriteArrayList<String>();
/**
* 目标方明名称
*/
private final String methodName;
/**
* 输入还是输出
* request
* response
*
* @see Type
*/
private Type type = Type.request;
/**
* 响应的操作对象
*/
private StreamObserverWrapper<v> response;
/**
* 请求的日志链路Id
*/
private final String traceId;
public StreamObserverWrapper(StreamObserver<v> own, String methodName, Type type, String traceId) {
this.type = type;
this.methodName = methodName;
this.own = own;
initTime = new DateTime();
this.traceId = traceId;
}
public StreamObserverWrapper(StreamObserver<v> own, String methodName, Type type, StreamObserverWrapper<v> response, String traceId) {
this.type = type;
this.methodName = methodName;
this.own = own;
this.response = response;
initTime = new DateTime();
this.traceId = traceId;
}
@Override
public void onNext(v value) {
try {
MDC.put(KEY_TRACE_ID, traceId);
String print = PRINTER.print(value);
nextValueList.add(print);
log.debug("nextValue :[{}]", StrUtil.sub(print, 0, getAdjustLength()));
own.onNext(value);
} catch (InvalidProtocolBufferException e) {
log.warn("on next print error:[{}]", e.getMessage(), e);
} finally {
MDC.remove(KEY_TRACE_ID);
}
}
@Override
public void onError(Throwable t) {
try {
MDC.put(KEY_TRACE_ID, traceId);
onCompletedTime = new DateTime();
Interval interval = new Interval(initTime, onCompletedTime);
log.info("Call API {} End () Type [{}] CarryParam => {}, RT:{} ms, NextValue => {}, Error:[{}]",
methodName, type,
StrUtil.sub(carryJsonParamList.toString(), 0, getAdjustLength()),
interval.toDurationMillis(),
StrUtil.sub(nextValueList.toString(), 0, getAdjustLength()), t.getMessage(), t);
own.onError(t);
} finally {
MDC.remove(KEY_TRACE_ID);
}
}
@Override
public void onCompleted() {
try {
MDC.put(KEY_TRACE_ID, traceId);
onCompletedTime = new DateTime();
Interval interval = new Interval(initTime, onCompletedTime);
if (type == Type.request) {
// 把客户端流当前获得的所有输入参数传递给response
response.getCarryJsonParamList().addAll(getNextValueList());
}
log.info("Call API {} End () Type [{}] CarryParam => {}, RT:{} ms, NextValue => {}",
methodName, type,
StrUtil.sub(carryJsonParamList.toString(), 0, getAdjustLength()),
interval.toDurationMillis(), StrUtil.sub(nextValueList.toString(), 0, getAdjustLength()));
own.onCompleted();
} finally {
MDC.remove(KEY_TRACE_ID);
}
}
public List<String> getNextValueList() {
return nextValueList;
}
public DateTime getOnCompletedTime() {
return onCompletedTime;
}
public DateTime getInitTime() {
return initTime;
}
public List<String> getCarryJsonParamList() {
return carryJsonParamList;
}
/**
* 打印的长度
*/
protected int getAdjustLength() {
return ADJ_LEN;
}
/**
* 包装的是输入还是输出
*/
public enum Type {
/**
* 代表请求客户端
*/
request,
/**
* 代表响应服务端
*/
response;
}
}
日记切面:
package com.aniu.inspection.config.aop;
import com.google.protobuf.Message;
import com.aniu.inspection.grpc.extension.StreamObserverWrapper;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.UUID;
/**
* @author pengyy
* @since 2022年7月4日
* grpc调用的日志切面
*/
@Aspect
@Order(1)
@Component
public class GrpcLogAspect {
private static final Logger LOGGER = LoggerFactory.getLogger(GrpcLogAspect.class);
/**
* 请求日志的链路id key
*/
private static final String KEY_TRACE_ID = "requestId";
@Pointcut("execution(* com.aniu.inspection.grpc.server.*.*(..))")
public void apiLogAop() {
}
@Around("apiLogAop()")
public Object aroundApi(ProceedingJoinPoint point) throws Throwable {
return log(point);
}
private Object log(ProceedingJoinPoint point) throws Throwable {
// 请求的日志链路Id
String traceId = UUID.randomUUID().toString();
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod();
String methodMerge = point.getSignature().getDeclaringTypeName() + "." + point.getSignature().getName();
final Object[] args = point.getArgs();
Object response;
// 获取类上的注解
GrpcService annotation = point.getTarget().getClass().getAnnotation(GrpcService.class);
try {
MDC.put(KEY_TRACE_ID, traceId);
LOGGER.info("GrpcLogAspect traceId:{},method:{}", traceId, methodMerge);
if (annotation != null) {
if (method.getReturnType() == StreamObserver.class
&& args.length == 1 &&
args[0] instanceof StreamObserver) {
// 存在客户端流
StreamObserverWrapper<Message> streamObserverWrapper = new StreamObserverWrapper<Message>((StreamObserver<Message>) args[0], methodMerge, StreamObserverWrapper.Type.response, traceId);
Object[] argsReplace = {streamObserverWrapper};
response = point.proceed(argsReplace);
if (response instanceof StreamObserver) {
StreamObserver<Message> observerWrapper = (StreamObserver<Message>) response;
return new StreamObserverWrapper<>(observerWrapper, methodMerge, StreamObserverWrapper.Type.request, streamObserverWrapper, traceId);
}
} else if (method.getReturnType() == void.class
&& args.length == 2
&& (args[1] instanceof StreamObserver)) {
StreamObserverWrapper<Message> streamObserverWrapper = new StreamObserverWrapper<Message>((StreamObserver<Message>) args[1], methodMerge, StreamObserverWrapper.Type.response, traceId);
Object[] argsReplace = {args[0], streamObserverWrapper};
return point.proceed(argsReplace);
}
}
// 非grpc调用方法
return point.proceed();
} finally {
MDC.remove(KEY_TRACE_ID);
}
}
}
proto文件:
syntax = "proto3";
import "google/protobuf/empty.proto";
import "google/protobuf/timestamp.proto";
import "inspectionmasterplan.proto";
option java_multiple_files = true;
option java_package = "com.aniu.inspection.grpc";
package grpc.test;
service ModuleTest{
// (普通模式 )
rpc inspectionPlanListByMasterId(InspectionPlanListByMasterDTO) returns(InspectionPlanListByMasterResponse);
// (服务端流返回)
rpc inspectionPlanListByMasterIdAndOnlyServerStream(InspectionPlanListByMasterDTO) returns(stream InspectionPlanByMasterDTO);
// (客户端流返回)
rpc inspectionPlanListByMasterIdAndOnlyClientStream(stream InspectionPlanListByMasterDTO) returns(InspectionPlanListByMasterResponse);
// (双服务端流返回)
rpc inspectionPlanListByMasterIdAndServerStream(stream InspectionPlanListByMasterDTO) returns(stream InspectionPlanByMasterDTO);
}