一.背景

Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置,从而使开发人员不再需要定义样板化的配置。通过这种方式,Spring Boot致力于在蓬勃发展的快速应用开发领域(rapid application development)成为领导者。
Grpc 由 google 开发,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。
项目定位是电商平台和WMS系统中间的插件服务,wms采用.net语言开发,电商平台采用java开发,所以出现了多语言间的数据交换,开始考虑使用json协议,方便快捷,但是考虑到效率和系统发展的问题,考虑使用RPC框架,斟酌之后敲定为GRPC。
但是,我们拓展服务使用的SpringBoot,Grpc和SpringBoot集成的文章不是很多,大部分都是采用github上*-springboot.grpc.starter的项目,看了一下,并不是很感兴趣,所以自己根据官网的demo,尝试与SpringBoot集成,所以在这和大家分享下

二. 准备工作

开发环境

Spring Boot 2.0.5.RELEASE Grpc 1.15.0 Inteliji Idea 2018.3

项目截图

【20200127】SpringBoot   Grpc - 图1

三.实现过程

1. 配置SpringBoot项目

  • Pom文件增加

    1. <parent>
    2. <groupId>org.springframework.boot</groupId>
    3. <artifactId>spring-boot-starter-parent</artifactId>
    4. <version>2.0.5.RELEASE</version>
    5. </parent>
    6. <dependencies>
    7. <dependency>
    8. <groupId>org.springframework.boot</groupId>
    9. <artifactId>spring-boot-starter-web</artifactId>
    10. </dependency>
    11. <dependency>
    12. <groupId>org.springframework.boot</groupId>
    13. <artifactId>spring-boot-starter-test</artifactId>
    14. </dependency>
    15. </dependencies>
  • 编写启动类

    1. public static void main(String[] args) {
    2. // 启动SpringBoot web
    3. SpringApplication.run(Launcher.class, args);
    4. }

    2. 增加GRPC支持和GRPC代码生成工具,集成GrpcServer端

  • 增加POM文件

    1. <dependency>
    2. <groupId>io.grpc</groupId>
    3. <artifactId>grpc-netty-shaded</artifactId>
    4. <version>1.15.0</version>
    5. </dependency>
    6. <dependency>
    7. <groupId>io.grpc</groupId>
    8. <artifactId>grpc-protobuf</artifactId>
    9. <version>1.15.0</version>
    10. </dependency>
    11. <dependency>
    12. <groupId>io.grpc</groupId>
    13. <artifactId>grpc-stub</artifactId>
    14. <version>1.15.0</version>
    15. </dependency>
  • 增加maven工具

    1. <build>
    2. <extensions>
    3. <extension>
    4. <groupId>kr.motd.maven</groupId>
    5. <artifactId>os-maven-plugin</artifactId>
    6. <version>1.5.0.Final</version>
    7. </extension>
    8. </extensions>
    9. <plugins>
    10. <plugin>
    11. <groupId>org.xolstice.maven.plugins</groupId>
    12. <artifactId>protobuf-maven-plugin</artifactId>
    13. <version>0.5.1</version>
    14. <configuration>
    15. <protocArtifact>com.google.protobuf:protoc:3.5.1-1:exe:${os.detected.classifier}</protocArtifact>
    16. <pluginId>grpc-java</pluginId>
    17. <pluginArtifact>io.grpc:protoc-gen-grpc-java:1.15.0:exe:${os.detected.classifier}</pluginArtifact>
    18. </configuration>
    19. <executions>
    20. <execution>
    21. <goals>
    22. <goal>compile</goal>
    23. <goal>compile-custom</goal>
    24. </goals>
    25. </execution>
    26. </executions>
    27. </plugin>
    28. </plugins>
    29. </build>
  • 编写Server端实现类

    1. public class HelloWorldService extends HelloWorldServiceGrpc.HelloWorldServiceImplBase {
    2. @Override
    3. public void welcome(HelloWorld.NameRequest request, StreamObserver<HelloWorld.EchoResponse> responseObserver) {
    4. HelloWorld.EchoResponseOrBuilder echoResponseOrBuilder = HelloWorld.EchoResponse.newBuilder();
    5. ((HelloWorld.EchoResponse.Builder) echoResponseOrBuilder).setMergename("welcome " + request.getName());
    6. responseObserver.onNext(((HelloWorld.EchoResponse.Builder) echoResponseOrBuilder).build());
    7. responseObserver.onCompleted();
    8. }
    9. }
  • 增加Grpc启动器

    1. @Component("grpcLauncher")
    2. public class GrpcLauncher {
    3. private Logger logger = LoggerFactory.getLogger(Launcher.class);
    4. /**
    5. * 定义Grpc Server
    6. */
    7. private Server server;
    8. @Value("${grpc.server.port}")
    9. private Integer grpcServerPort;
    10. /**
    11. * GRPC 服务启动方法
    12. * @param grpcServiceBeanMap
    13. */
    14. public void grpcStart(Map<String, Object> grpcServiceBeanMap) {
    15. try{
    16. ServerBuilder serverBuilder = ServerBuilder.forPort(grpcServerPort);
    17. for (Object bean : grpcServiceBeanMap.values()){
    18. serverBuilder.addService((BindableService) bean);
    19. logger.info(bean.getClass().getSimpleName() + " is regist in Spring Boot");
    20. }
    21. server = serverBuilder.build().start();
    22. logger.info("grpc server is started at " + grpcServerPort);
    23. server.awaitTermination();
    24. Runtime.getRuntime().addShutdownHook(new Thread(()->{grpcStop();}));
    25. } catch (IOException e){
    26. e.printStackTrace();
    27. } catch (InterruptedException e) {
    28. e.printStackTrace();
    29. }
    30. }
    31. /**
    32. * GRPC 服务Stop方法
    33. */
    34. private void grpcStop(){
    35. if (server != null){
    36. server.shutdownNow();
    37. }
    38. }
    39. }
  • 添加自定义注解用于扫描Grpc服务

    1. /**
    2. * 自定义注解,用于获取Spring扫描到的类
    3. */
    4. @Target({ElementType.TYPE})
    5. @Retention(RetentionPolicy.RUNTIME)
    6. @Documented
    7. @Component
    8. public @interface GrpcService {
    9. }
  • 在SpringBoot中增加Grpc启动器,并将Spring管理的类,添加到Grpc服务中

    1. /**
    2. * Spring Boot 启动器
    3. */
    4. @SpringBootApplication
    5. public class Launcher {
    6. public static void main(String[] args) {
    7. // 启动SpringBoot web
    8. ConfigurableApplicationContext configurableApplicationContext = SpringApplication.run(Launcher.class, args);
    9. Map<String, Object> grpcServiceBeanMap = configurableApplicationContext.getBeansWithAnnotation(GrpcService.class);
    10. GrpcLauncher grpcLauncher = configurableApplicationContext.getBean("grpcLauncher",GrpcLauncher.class);
    11. grpcLauncher.grpcStart(grpcServiceBeanMap);
    12. }
    13. }

    至此Server端,集成完毕

【20200127】SpringBoot   Grpc - 图2

3. 增加Client端

  • 获取Chanel

    1. @Component
    2. public class GrpcClientMananer {
    3. @Value("${grpc.client.host}")
    4. private String host;
    5. @Value("${grpc.client.port}")
    6. private Integer port;
    7. public ManagedChannel getChannel(){
    8. ManagedChannel channel = ManagedChannelBuilder.forAddress(host,port)
    9. .disableRetry()
    10. .idleTimeout(2, TimeUnit.SECONDS)
    11. .build();
    12. return channel;
    13. }
    14. }
  • 调用方式

    1. @Component public class HelloWorldClient {
    2. @Autowired
    3. private GrpcClientMananer grpcClientMananer;
    4. public void call(){
    5. ManagedChannel channel = grpcClientMananer.getChannel();
    6. HelloWorld.NameRequestOrBuilder nameRequestOrBuilder = HelloWorld.NameRequest.newBuilder();
    7. ((HelloWorld.NameRequest.Builder) nameRequestOrBuilder).setName("Geek");
    8. HelloWorldServiceGrpc.HelloWorldServiceBlockingStub stub = HelloWorldServiceGrpc.newBlockingStub(channel);
    9. HelloWorld.EchoResponse echoResponse = stub.welcome(((HelloWorld.NameRequest.Builder) nameRequestOrBuilder).build());
    10. System.out.println(echoResponse.getMergename());
    11. }
    12. }


参考资料