Skip to content

Latest commit

 

History

History
520 lines (398 loc) · 16.8 KB

File metadata and controls

520 lines (398 loc) · 16.8 KB

logo Spring Boot Starter for gRPC

简介

一个简洁, 清晰, 易扩展和高度可定制的 gRPC spring-boot 风格的 spring-boot starter.

它需要 Spring Boot 2+ and JDK1.8+.

特性

  • 简单使用 @GrpcService, @GrpcServerInterceptor 和spring注解如 @Component 来注册gRPC service和server interceptors;

  • 简单使用 @GrpcClient, @GrpcClientInterceptor 和spring注解如 @Component 来注册gRPC stub, channel以及client interceptors;

  • 支持多server服务;

  • 提供简单的方式进行客户端负载均衡;

  • 细粒度的servers/clients以及它们的interceptors的控制.

获取

Gradle

Get grpc-spring-boot:
implementation("xyz.srclab.grpc.spring.boot:grpc-spring-boot-starter-server:0.0.1")
implementation("xyz.srclab.grpc.spring.boot:grpc-spring-boot-starter-client:0.0.1")
implementation("xyz.srclab.grpc.spring.boot:grpc-spring-boot-starter-web:0.0.1")
Use bom:
api platform("xyz.srclab.grpc.spring.boot:grpc-spring-boot-starter-bom:0.0.1")

Maven

Get grpc-spring-boot:
<dependencies>
  <dependency>
    <groupId>xyz.srclab.grpc.spring.boot</groupId>
    <artifactId>grpc-spring-boot-starter-server</artifactId>
    <version>0.0.1</version>
  </dependency>
  <dependency>
    <groupId>xyz.srclab.grpc.spring.boot</groupId>
    <artifactId>grpc-spring-boot-starter-client</artifactId>
    <version>0.0.1</version>
  </dependency>
  <dependency>
    <groupId>xyz.srclab.grpc.spring.boot</groupId>
    <artifactId>grpc-spring-boot-starter-web</artifactId>
    <version>0.0.1</version>
  </dependency>
</dependencies>
Use bom:
<dependencyManagement>
  <dependencies>
    <dependency>
      <groupId>xyz.srclab.grpc.spring.boot</groupId>
      <artifactId>grpc-spring-boot-starter-bom</artifactId>
      <version>0.0.1</version>
      <type>pom</type>
      <scope>import</scope>
    </dependency>
  </dependencies>
</dependencyManagement>

使用

Server

创建一个服务

我们首先在application.yml (或者 .yaml, .properties)添加server的属性:

grpc:
  server:
    servers:
      server1:
        host: 127.0.0.1
        port: 6565

现在我们有了一个叫 server1 的服务, 在地址: 127.0.0.1:6565 上. 接下来我们在 server1 上添加service:

@Service
public class DefaultHelloService extends DefaultHelloServiceGrpc.DefaultHelloServiceImplBase {

    @Override
    public void hello(HelloRequest request, StreamObserver<HelloResponse> responseObserver) {
        responseObserver.onNext(HelloResponse.newBuilder()
            .setMessage("DefaultHelloService")
            .setThreadName(Thread.currentThread().getName())
            .build()
        );
        responseObserver.onCompleted();
    }
}

现在 server1 有了一个 gRPC service DefaultHelloService. 如果我们运行项目, server1 将会自动启动.

多Server服务

如果我们需要在端口 65656566 上都开启服务, 并且他们共享主机 localhost:

grpc:
  server:
    defaults:
      host: 127.0.0.1
    servers:
      server1:
        port: 6565
      server2:
        port: 6566

defaults 属性的子属性和 server 属性的子属性相同. server 属性将会自动注入 defaults 属性, 除了被覆盖配置的属性.

@GrpcService

默认情况下, 如果一个 gRPC service 类被 @Service 或者其他 spring-boot 注解所注释, 它将为所有的服务工作. 因此, DefaultHelloService 将同时为 server1server2 工作. 如果我们希望 DefaultHelloService 只为 server1 工作:

@GrpcService("server1")
public class DefaultHelloService{}

@GrpcService(serverPatterns = "server1")
public class DefaultHelloService{}

@GrpcService(serverPatterns = "*1")
public class DefaultHelloService{}

@GrpcService 可以通过 value or serverPatterns 属性指定它愿意工作的服务名, 并且它支持 ant-pattern. 现在 DefaultHelloService 只为 server1 工作了.

@GrpcServerInterceptor

添加拦截器和添加服务一样:

@Component
public class DefaultServerInterceptor extends BaseServerInterceptor {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
        ServerCall<ReqT, RespT> call, Metadata headers, ServerCallHandler<ReqT, RespT> next) {
        if (Objects.equals(call.getMethodDescriptor().getServiceName(), "HelloService2")) {
            helloService2.addInterceptorTrace("DefaultServerInterceptor");
        }
        return super.interceptCall(call, headers, next);
    }
}

DefaultServerInterceptor 将会为所有的 gRPC services (DefaultHelloService) 工作, 想要限制它, 使用 @GrpcServerInterceptor:

@GrpcServerInterceptor(value = "*hello*", order = -2)
public class DefaultServerInterceptor{}

@GrpcServerInterceptor(servicePatterns = "*hello*", order = -3)
public class DefaultServerInterceptor{}

就像 @GrpcService, @GrpcServerInterceptor 可以指定 service bean 的名字, 并且支持 ant-pattern. order 属性指定调用殊勋, 从低到高. 现在, DefaultServerInterceptor 只为匹配 *hello* 的服务提供拦截了.

AbstractServerInterceptor and SimpleServerInterceptor

ServerInterceptor 足以令人困惑 (想想看它的嵌套调用和回调顺序). 为了方便开发, 这个starter 提供 AbstractServerInterceptorSimpleServerInterceptor.

AbstractServerInterceptorServerInterceptor 的快捷实现, 提供一系列的回调方法以供重写, 并且有一个简单的调用顺序: intercept1 → intercept2 → onMessage2 → onMessage1 (具体请参阅 javadoc).

SimpleServerInterceptor 是一个接口, 提供和 AbstractServerInterceptor 一样的回调方法一共重写.

区别:

  • 每个 AbstractServerInterceptor 都是一个 ServerInterceptor 实例, 但是所有的 SimpleServerInterceptor 对于每个 gRPC service 都将被合并成一个 ServerInterceptor;

  • 回调顺序是: intercept1 → intercept2 → onMessage1 → onMessage2 (具体请参阅 javadoc).

MetadataServerInterceptor

MetadataServerInterceptor 是一个简单的 ServerInterceptor 用来处理 metadata (headers).

DefaultGrpcServerConfigurer and DefaultGrpcServerConfigureHelper

默认情况下, 这个starter使用 InProcessBuilder, NettyServerBuilderShadedNettyServerBuilder 来创建 gRPC server. 如果你想要定制这个过程, 创建一个 DefaultGrpcServerConfigurer bean 并且使用 bean DefaultGrpcServerConfigureHelper 来辅助设置.

GrpcServerFactory and DefaultGrpcServerFactory

这个starter使用 GrpcServerFactory 来创建 gRPC server, 它默认的实现是 DefaultGrpcServerFactory. 如果你想要定制这个过程, 创建一个 GrpcServerFactory bean 来替代.

Note
DefaultGrpcServerConfigurer 将会失效如果你创建了定制的 GrpcServerFactory bean, 但是 DefaultGrpcServerConfigureHelper 仍然可以使用.

GrpcServersFactory and DefaultGrpcServersFactory

这个starter使用 GrpcServersFactory 来创建所有的 gRPC server, 它默认的实现是 DefaultGrpcServersFactory. 如果你想要定制这个过程, 创建一个 GrpcServersFactory bean 来替代.

Note
DefaultGrpcServerFactoryDefaultGrpcServerConfigurer 将会失效如果你创建了定制的 GrpcServersFactory bean, 但是`DefaultGrpcServerConfigureHelper` 仍然可以使用.

Server配置属性表

Table 1. GrpcServersProperties
Key Type Default Comment

defaults

ServerProperties

servers

Map<String, ServerProperties>

needGrpcAnnotation

Boolean

false

Whether gRPC bean (BindableService and ServerInterceptor) should be annotated by gRPC annotation (GrpcService and GrpcServerInterceptor).

This means spring-boot annotation such as @Component is invalid for gRPC bean.

Default is false.

Table 2. ServerProperties
Key Type Default Comment

inProcess

Boolean

false

useShaded

Boolean

false

host

String

localhost

port

Int

6565

threadPoolBeanName

String

Thread pool bean name for gRPC executor.

maxConcurrentCallsPerConnection

Int

initialFlowControlWindow

Int

flowControlWindow

Int

maxMessageSize

Int

maxHeaderListSize

Int

keepAliveTimeInNanos

Long

keepAliveTimeoutInNanos

Long

maxConnectionIdleInNanos

Long

maxConnectionAgeInNanos

Long

maxConnectionAgeGraceInNanos

Long

permitKeepAliveWithoutCalls

Boolean

permitKeepAliveTimeInNanos

Long

sslCertChainClassPath

String

Same classpath and file properties are alternative and classpath first

sslPrivateKeyClassPath

String

Same classpath and file properties are alternative and classpath first

sslTrustCertCollectionClassPath

String

Same classpath and file properties are alternative and classpath first

sslCertChainFile

String

Same classpath and file properties are alternative and classpath first

sslPrivateKeyFile

String

Same classpath and file properties are alternative and classpath first

sslTrustCertCollectionFile

String

Same classpath and file properties are alternative and classpath first

sslPrivateKeyPassword

String

sslClientAuth

String

Auth enum with case-ignore: none, optional or require.

Default is none.

Client

创建一个客户端

我们首先在application.yml (或者 .yaml, .properties)添加client的属性:

grpc:
  client:
    clients:
      client1:
        target: 127.0.0.1:6565

现在我们有了一个client叫 client1, target: 127.0.0.1:6565. 接着我们使用 client1 添加stub和channel:

public class TestBean {

    @GrpcClient
    private DefaultHelloServiceGrpc.DefaultHelloServiceBlockingStub stub1;

    @GrpcClient
    private Channel channel1;
}

现在, stub1channel1 在项目启动时将会使用 client1 的属性自动注入.

多客户端:

如果我们需要两个客户端, 用target 127.0.0.1:6565127.0.0.1:6566:

grpc:
  client:
    clients:
      client1:
        target: 127.0.0.1:6565
      client2:
        target: 127.0.0.1:6566

然后:

public class TestBean {

    @GrpcClient
    private DefaultHelloServiceGrpc.DefaultHelloServiceBlockingStub defaultStub;

    @GrpcClient("client1")
    private HelloServiceXGrpc.HelloServiceXBlockingStub client1Stub;

    @GrpcClient("client2")
    private HelloService2Grpc.HelloService2BlockingStub client2Stub;
}

如果client的名字在 @GrpcClient 上没有被指定, 它将使用配置的第一个客户端 (这里是 client1).

Note
客户端配置也会继承 defaults 属性就像 多Server服务.

负载均衡

设置 load-balance target:

grpc:
  client:
    clients:
      lb:
        target: lb:127.0.0.1/127.0.0.1:6666,127.0.0.1/127.0.0.1:6667

现在, client lb 被配置成负载均衡了.

Note
负载均衡的语法: lb:authority1/host1:port1,authority2/host2:port2…​

ClientInterceptor

申明一个 ClientInterceptor 只需要给一个 ClientInterceptor 类型的bean:

@Component
public class DefaultClientInterceptor extends BaseClientInterceptor {

    @Override
    public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
        MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
        if (Objects.equals(method.getServiceName(), "HelloService2")) {
            traceService.addInterceptorTrace("DefaultClientInterceptor");
        }
        return super.interceptCall(method, callOptions, next);
    }
}

现在我们有了一个 DefaultClientInterceptor 作为 ClientInterceptor, 它将为所有的client服务.

@ClientInterceptor

要细粒度的设置拦截器, use @GrpcServerInterceptor:

@GrpcClientInterceptor(value = "*2", order = 0)
public class DefaultClientInterceptor{}

@GrpcClientInterceptor(clientPatterns = "*2", order = -3)
public class DefaultClientInterceptor{}

value 或者 clientPatterns 指定client DefaultClientInterceptor 为谁工作, 支持 ant-pattern. 现在, 它只为名字匹配 \*2 的client工作.

AbstractClientInterceptor and SimpleClientInterceptor

ClientInterceptor 足以令人困惑 (想想看它的嵌套调用和回调顺序). 为了方便开发, 这个starter 提供 AbstractClientInterceptorSimpleClientInterceptor.

AbstractClientInterceptorClientInterceptor 的快捷实现, 提供一系列的回调方法以供重写, 并且有一个简单的调用顺序: intercept1 → intercept2 → onClose2 → onClose1 (具体请参阅 javadoc).

SimpleClientInterceptor 是一个接口, 提供和 AbstractClientInterceptor 一样的回调方法一共重写.

区别:

  • 每个 AbstractClientInterceptor 都是一个 ClientInterceptor 实例, 但是所有的 SimpleClientInterceptor 对于每个 gRPC service 都将被合并成一个 ClientInterceptor;

  • 回调顺序是: intercept1 → intercept2 → onClose1 → onClose2 (具体请参阅 javadoc).

DefaultGrpcChannelConfigurer and DefaultGrpcChannelConfigureHelper

默认情况下, 这个starter使用 InProcessBuilder, NettyServerBuilderShadedNettyServerBuilder 来创建 gRPC client. 如果你想要定制这个过程, 创建一个 DefaultGrpcChannelConfigurer bean 并且使用 bean DefaultGrpcChannelConfigureHelper 来辅助设置.

GrpcChannelFactory, DefaultGrpcChannelFactory, GrpcStubFactory and DefaultGrpcStubFactory

这个starter使用 GrpcChannelFactory 来创建 gRPC stub, 使用 GrpcStubFactory 来创建 gRPC channel. 默认实现 DefaultGrpcChannelFactoryDefaultGrpcStubFactory. 如果你想要定制这个过程, 创建一个 GrpcChannelFactory bean 或者 GrpcStubFactory bean.

Note
DefaultGrpcChannelConfigurer 将会失效如果你创建了定制的 GrpcChannelFactory bean, 但是 DefaultGrpcChannelConfigureHelper 仍然可以使用.

GrpcTargetResolver and DefaultGrpcTargetResolver

这个starter会注册 LbNameResolverProvider 来解析负载均衡的 target (lb:authority/host1:port1,host2:port2…​). 默认情况下, LbNameResolverProvider 使用 DefaultGrpcTargetResolver 来解析, 想要定制这个过程, 创建一个 GrpcTargetResolver bean 来替代.

Client配置属性表

Table 3. GrpcClientsProperties
Key Type Default Comment

defaults

ClientProperties

servers

Map<String, ClientProperties>

needGrpcAnnotation

Boolean

false

Whether gRPC bean ClientInterceptor should be annotated by gRPC annotation (GrpcClientInterceptor).

This means spring-boot annotation such as @Component is invalid for gRPC bean.

Default is false.

Table 4. ClientProperties
Key Type Default Comment

inProcess

Boolean

false

useShaded

Boolean

false

target

String

localhost:6565

Address or load balance (lb:authority/host1:port1,host2:port2…​)

threadPoolBeanName

String

Thread pool bean name for gRPC executor.

initialFlowControlWindow

Int

flowControlWindow

Int

maxMessageSize

Int

maxHeaderListSize

Int

keepAliveTimeInNanos

Long

keepAliveTimeoutInNanos

Long

keepAliveWithoutCalls

Boolean

deadlineAfterInNanos

Long

loadBalancingPolicy

String

round_robin

Load balance policy: round_robin, pick_first.

Default is round_robin.

sslCertChainClassPath

String

Same classpath and file properties are alternative and classpath first

sslPrivateKeyClassPath

String

Same classpath and file properties are alternative and classpath first

sslTrustCertCollectionClassPath

String

Same classpath and file properties are alternative and classpath first

sslCertChainFile

String

Same classpath and file properties are alternative and classpath first

sslPrivateKeyFile

String

Same classpath and file properties are alternative and classpath first

sslTrustCertCollectionFile

String

Same classpath and file properties are alternative and classpath first

sslPrivateKeyPassword

String

sslClientAuth

String

Auth enum with case-ignore: none, optional or require.

Default is none.

Web

grpc-spring-boot-starter-web 用来让 Controller 支持protobuf的 Message 类型.

默认情况下, 它使用 Jackson2ObjectMapperBuilderCustomizer 来实现.