应用启动类很简单:
package com.bolingcavalry.grpctutorials; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class LocalServerApplication { public static void main(String[] args) { SpringApplication.run(LocalServerApplication.class, args); } }接下来是最重要的service类,gRPC服务在此处对外暴露出去,完整代码如下,有几处要注意的地方稍后提到:
package com.bolingcavalry.grpctutorials; import com.bolingcavalry.grpctutorials.lib.HelloReply; import com.bolingcavalry.grpctutorials.lib.SimpleGrpc; import net.devh.boot.grpc.server.service.GrpcService; import java.util.Date; @GrpcService public class GrpcServerService extends SimpleGrpc.SimpleImplBase { @Override public void sayHello(com.bolingcavalry.grpctutorials.lib.HelloRequest request, io.grpc.stub.StreamObserver<com.bolingcavalry.grpctutorials.lib.HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder().setMessage("Hello " + request.getName() + ", " + new Date()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } }上述GrpcServerService.java中有几处需要注意:
是使用@GrpcService注解,再继承SimpleImplBase,这样就可以借助grpc-server-spring-boot-starter库将sayHello暴露为gRPC服务;
SimpleImplBase是前文中根据proto自动生成的java代码,在grpc-lib模块中;
sayHello方法中处理完毕业务逻辑后,调用HelloReply.onNext方法填入返回内容;
调用HelloReply.onCompleted方法表示本次gRPC服务完成;
至此,gRPC服务端编码就完成了,咱们接着开始客户端开发;
调用gRPC在父工程grpc-turtorials下面新建名为local-client的模块,其build.gradle内容如下,注意要使用spingboot插件、依赖grpc-client-spring-boot-starter库:
plugins { id 'org.springframework.boot' } dependencies { implementation 'org.projectlombok:lombok' implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'net.devh:grpc-client-spring-boot-starter' implementation project(':grpc-lib') }应用配置文件grpc-tutorials/local-client/src/main/resources/application.yml,注意address的值就是gRPC服务端的信息,我这里local-server和local-client在同一台电脑上运行,请您根据自己情况来设置:
server: port: 8080 spring: application: name: local-grpc-client grpc: client: # gRPC配置的名字,GrpcClient注解会用到 local-grpc-server: # gRPC服务端地址 address: 'static://127.0.0.1:9898' enableKeepAlive: true keepAliveWithoutCalls: true negotiationType: plaintext-接下来要创建下图展示的类,按序号顺序创建:
首先是拦截类LogGrpcInterceptor,与服务端的拦截类差不多,不过实现的接口不同:
package com.bolingcavalry.grpctutorials; import io.grpc.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class LogGrpcInterceptor implements ClientInterceptor { private static final Logger log = LoggerFactory.getLogger(LogGrpcInterceptor.class); @Override public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) { log.info(method.getFullMethodName()); return next.newCall(method, callOptions); } }为了让拦截类能够正常工作,即发起gRPC请求的时候被执行,需要新增一个配置类:
package com.bolingcavalry.grpctutorials; import io.grpc.ClientInterceptor; import net.devh.boot.grpc.client.interceptor.GrpcGlobalClientInterceptor; import org.springframework.context.annotation.Configuration; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; @Order(Ordered.LOWEST_PRECEDENCE) @Configuration(proxyBeanMethods = false) public class GlobalClientInterceptorConfiguration { @GrpcGlobalClientInterceptor ClientInterceptor logClientInterceptor() { return new LogGrpcInterceptor(); } }启动类:
package com.bolingcavalry.grpctutorials; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class LocalGrpcClientApplication { public static void main(String[] args) { SpringApplication.run(LocalGrpcClientApplication.class, args); } }接下来是最重要的服务类GrpcClientService,有几处要注意的地方稍后会提到:
package com.bolingcavalry.grpctutorials; import com.bolingcavalry.grpctutorials.lib.HelloReply; import com.bolingcavalry.grpctutorials.lib.HelloRequest; import com.bolingcavalry.grpctutorials.lib.SimpleGrpc; import io.grpc.StatusRuntimeException; import net.devh.boot.grpc.client.inject.GrpcClient; import org.springframework.stereotype.Service; @Service public class GrpcClientService { @GrpcClient("local-grpc-server") private SimpleGrpc.SimpleBlockingStub simpleStub; public String sendMessage(final String name) { try { final HelloReply response = this.simpleStub.sayHello(HelloRequest.newBuilder().setName(name).build()); return response.getMessage(); } catch (final StatusRuntimeException e) { return "FAILED with " + e.getStatus().getCode().name(); } } }上述GrpcClientService类有几处要注意的地方:
用@Service将GrpcClientService注册为spring的普通bean实例;
用@GrpcClient修饰SimpleBlockingStub,这样就可以通过grpc-client-spring-boot-starter库发起gRPC调用,被调用的服务端信息来自名为local-grpc-server的配置;
SimpleBlockingStub来自前文中根据helloworld.proto生成的java代码;
SimpleBlockingStub.sayHello方法会远程调用local-server应用的gRPC服务;