gRPC Spring Boot StartergRPC 框架的 Spring Boot 启动器模块
gRPC 框架的 Spring Boot 启动器模块
特点
-
使用
@ GrpcService
自动创建并运行一个 gRPC 服务,内嵌在 spring-boot 应用中 -
使用
@ GrpcClient
自动创建和管理你的channel
和stub
-
支持 Spring Cloud(向 Consul 或 Eureka 或 Nacos 注册服务并获取gRPC服务信息)
-
支持 Spring Sleuth 进行链路跟踪(需要单独引入 brave-instrumentation-grpc)
-
支持对 server、client 分别设置全局拦截器或单个的拦截器
-
支持 metric (micrometer / actuator)
-
可以使用 (non-shaded) grpc-netty
版本
2.x.x.RELEASE 支持 Spring Boot 2.1+ & Spring Cloud Greenwich。
最新的版本:2.5.0.RELEASE
(使用 2.4.0.RELEASE
版本可以支持 Spring Boot 2.0.X & Spring Cloud Finchley).
1.x.x.RELEASE 支持 Spring Boot 1 & Spring Cloud Edgware 、Dalston、Camden。
最新的版本:1.4.2.RELEASE
注意: 此项目也可以在没有 Spring-Boot 的场景下使用,但需要手动的配置相关的 bean。
使用方式
gRPC server + client
如果使用的是 Maven,添加如下依赖
<dependency> <groupId>net.devh</groupId> <artifactId>grpc-spring-boot-starter</artifactId> <version>2.5.0.RELEASE</version> </dependency>
如果使用的 Gradle,添加如下依赖
dependencies { compile 'net.devh:grpc-spring-boot-starter:2.5.0.RELEASE' }
gRPC 服务端
如果使用的是 Maven,添加如下依赖
<dependency> <groupId>net.devh</groupId> <artifactId>grpc-server-spring-boot-starter</artifactId> <version>2.5.0.RELEASE</version> </dependency>
如果使用的 Gradle,添加如下依赖
dependencies { compile 'net.devh:grpc-server-spring-boot-starter:2.5.0.RELEASE' }
实现 gRPC server 的业务逻辑,并使用 @GrpcService
注解
@GrpcService public class GrpcServerService extends GreeterGrpc.GreeterImplBase { @Override public void sayHello(HelloRequest req, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder().setMessage("Hello ==> " + req.getName()).build(); responseObserver.onNext(reply); responseObserver.onCompleted(); } }
设置 gRPC 的 host 跟 port ,默认的监听的 port 是 9090。其他配置属性可以参考 settings。 所有的配置属性在 server 中使用需增加 grpc.server.
的前缀
服务端配置属性示例
grpc.server.port=9090 grpc.server.address=0.0.0.0 #grpc.server.inProcessName=test
对 Server 进行自定义
当前项目同样支持对 ServerBuilder
的自定义修改,需要在创建的过程中使用 GrpcServerConfigurer
beans。
@Bean public GrpcServerConfigurer keepAliveServerConfigurer() { return serverBuilder -> { if (serverBuilder instanceof NettyServerBuilder) { ((NettyServerBuilder) serverBuilder) .keepAliveTime(30, TimeUnit.SECONDS) .keepAliveTimeout(5, TimeUnit.SECONDS) .permitKeepAliveWithoutCalls(true); } }; }
Server-Security
支持使用 Spring-Security 加密你的 gRPC 应用。你只需要添加 Spring-Security(core 或者 config)依赖,然后根据需要再增加加密的配置
首先需要选择一个认证方案
-
BasicAuth(基础认证)
@Bean AuthenticationManager authenticationManager() { final List<AuthenticationProvider> providers = new ArrayList<>(); providers.add(...); // Possibly DaoAuthenticationProvider return new ProviderManager(providers); } @Bean GrpcAuthenticationReader authenticationReader() { final List<GrpcAuthenticationReader> readers = new ArrayList<>(); readers.add(new BasicGrpcAuthenticationReader()); return new CompositeGrpcAuthenticationReader(readers); }
-
Bearer Authentication (OAuth2/OpenID-Connect)
@Bean AuthenticationManager authenticationManager() { final List<AuthenticationProvider> providers = new ArrayList<>(); providers.add(...); // Possibly JwtAuthenticationProvider return new ProviderManager(providers); } @Bean GrpcAuthenticationReader authenticationReader() { final List<GrpcAuthenticationReader> readers = new ArrayList<>(); readers.add(new BearerAuthenticationReader(accessToken -> new BearerTokenAuthenticationToken(accessToken))); return new CompositeGrpcAuthenticationReader(readers); }
你可能还想定义自己的 GrantedAuthoritiesConverter ,将权限和角色的信息映射到 Spring Security 的
GrantedAuthority
中 -
Certificate Authentication(证书认证)
@Bean AuthenticationManager authenticationManager() { final List<AuthenticationProvider> providers = new ArrayList<>(); providers.add(new X509CertificateAuthenticationProvider(userDetailsService())); return new ProviderManager(providers); } @Bean GrpcAuthenticationReader authenticationReader() { final List<GrpcAuthenticationReader> readers = new ArrayList<>(); readers.add(new SSLContextGrpcAuthenticationReader()); return new CompositeGrpcAuthenticationReader(readers); }
相关的配置属性如下:
grpc.server.security.enabled=true grpc.server.security.certificateChain=file:certificates/server.crt grpc.server.security.privateKey=file:certificates/server.key grpc.server.security.trustCertCollection=file:certificates/trusted-clients-collection grpc.server.security.clientAuth=REQUIRE
-
使用
CompositeGrpcAuthenticationReader
类链式的调用多个认证方案 -
自定义认证方式(继承并实现
GrpcAuthenticationReader
类)
如何去保护你的这些服务
-
使用 Spring-Security 的注解
@Configuration @EnableGlobalMethodSecurity(proxyTargetClass = true, ...) public class SecurityConfiguration {
如果你想使用 Spring Security 相关的注解的话,
proxyTargetClass
属性是必须的! 但是你会受到一条警告,提示 MyServiceImpl#bindService() 方式是用 final 进行修饰的。 这条警告目前无法避免,但它是安全的,可以忽略它。 -
手动配置
@Bean AccessDecisionManager accessDecisionManager() { final List<AccessDecisionVoter<?>> voters = new ArrayList<>(); voters.add(new AccessPredicateVoter()); return new UnanimousBased(voters); } @Bean GrpcSecurityMetadataSource grpcSecurityMetadataSource() { final ManualGrpcSecurityMetadataSource source = new ManualGrpcSecurityMetadataSource(); source.set(MyServiceGrpc.getSecureMethod(), AccessPredicate.hasRole("ROLE_USER")); source.setDefault(AccessPredicate.permitAll()); return source; }
gRPC 客户端
如果使用的是 Maven,添加如下依赖
<dependency> <groupId>net.devh</groupId> <artifactId>grpc-client-spring-boot-starter</artifactId> <version>2.5.0.RELEASE</version> </dependency>
如果使用的 Gradle,添加如下依赖
dependencies { compile 'net.devh:grpc-client-spring-boot-starter:2.5.0.RELEASE' }
这里有三种方式去或得一个gRPC server的连接
-
使用
grpcChannelFactory.createChannel(serverName)
去创建一个Channel
,并创建一个自己的 gRPC stub.@Autowired private GrpcChannelFactory grpcChannelFactory; private GreeterGrpc.GreeterBlockingStub greeterStub; @PostConstruct public void init() { Channel channel = grpcChannelFactory.createChannel("gRPC server name"); greeterStub = GreeterGrpc.newBlockingStub(channel); }
-
通过在
Channel
类型的字段上加入@GrpcClient(serverName)
注解,并创建一个自己的 gRPC stub.- 不需要使用
@Autowired
或者@Inject
来进行注入
@GrpcClient("gRPC server name") private Channel channel; private GreeterGrpc.GreeterBlockingStub greeterStub; @PostConstruct public void init() { greeterStub = GreeterGrpc.newBlockingStub(channel); }
- 不需要使用
-
直接将
@GrpcClient(serverName)
注解加在调用客户端的 stub 上- 不需要使用
@Autowired
或者@Inject
来进行注入
@GrpcClient("gRPC server name") private GreeterGrpc.GreeterBlockingStub greeterStub;
- 不需要使用
注意: 你可以为多个 channels 和多个不同的 stubs 使用相同的 serverName (除非他们拦截器不一样).
然后你可以直接向服务端发起请求,如下:
HelloReply response = stub.sayHello(HelloRequest.newBuilder().setName(name).build());
可以单独为每一个 client 配置对应的 address 但在某些情况下,你可以调整默认的配置。 你可以通过 NameResolver.Factory
beans 去自定义默认的 url 映射,如果你没有配置这个 bean,那将会按照下面的方式进行解析:
- 如果存在一个
DiscoveryClient
的 bean,这时会使用 client name 去注册中心上进行获取对应服务的 address - 否则 client 端将使用
localhost
和9090
端口
其他的配置属性参考 settings,所有的配置文件在 client 端使用时需要增加 grpc.client.(serverName).
的前缀
你也可以配置多个目标地址,请求时会自动使用负载均衡
static://127.0.0.1:9090,[::1]:9090
你也可以使用服务发现去获取目标地址(要求一个 DiscoveryClient
bean)
discovery:///my-service-name
此外,你也可以使用 DNS 的方式去获取目标地址
dns:///example.com
同时,你也可以使用如下方式直接进程内访问
in-process:test
它会通过DNS将域名解析出所有真实的 IP 地址,通过使用这些真实的IP地址去做负载均衡。 需要注意的是 grpc-java
出于性能的考虑对 DNS 返回的结果做缓存。 有关这些和其他原生支持的 NameResolverProviders
参考官方文档 grpc-java sources
客户端配置属性示例
grpc.client.GLOBAL.enableKeepAlive=true grpc.client.(gRPC server name).address=static://localhost:9090 # Or grpc.client.myName.address=static://localhost:9090
GLOBAL
是一个特殊的常量,它可以用于对所有 Client 统一的设置属性。 属性覆盖的顺序:Client单独的属性 > GLOBAL
的属性 > 默认的属性
自定义 Client
This library also supports custom changes to the ManagedChannelBuilder
and gRPC client stubs during creation by creating GrpcChannelConfigurer
and StubTransformer
beans. 当前项目支持对 ManagedChannelBuilder
的自定义,在 gRPC client stub创建的过程中,通过使用 GrpcChannelConfigurer
或 StubTransformer
bean 来完成自定义操作
@Bean public GrpcChannelConfigurer keepAliveClientConfigurer() { return (channelBuilder, name) -> { if (channelBuilder instanceof NettyChannelBuilder) { ((NettyChannelBuilder) channelBuilder) .keepAliveTime(15, TimeUnit.SECONDS) .keepAliveTimeout(5, TimeUnit.SECONDS); } }; } @Bean public StubTransformer authenticationStubTransformer() { return (clientName, stub) -> stub.withCallCredentials(grpcCredentials(clientName)); }
客户端认证
注意: 以下列出的一些方法仅仅适用于通过注入得到的 stubs,如果你通过注入 Channel,手动的在去创建 stubs,这就需要你自己手动的 去配置凭证。然而你同样能从目前所提供的一些辅助类方法中收益。
客户端有许多不同的认证方式,我们只需定义一个类型为 CallCredentials
的 bean,它会自动作用于身份验证。目前通过一些辅助方法可以支持 下列的认证方式:
-
BasicAuth
@Bean CallCredentials grpcCredentials() { return CallCredentialsHelper.basicAuth(username, password); }
-
Bearer Authentication (OAuth2, OpenID-Connect)
@Bean CallCredentials grpcCredentials() { return CallCredentialsHelper.bearerAuth(token); }
-
Certificate Authentication
需要一些配置属性:
#grpc.client.test.security.authorityOverride=localhost #grpc.client.test.security.trustCertCollection=file:certificates/trusted-servers-collection grpc.client.test.security.clientAuthEnabled=true grpc.client.test.security.certificateChain=file:certificates/client.crt grpc.client.test.security.privateKey=file:certificates/client.key
-
为每个 client 使用不同的认证
通过定义一个
StubTransformer
bean 来代替原有的CallCredentials
bean@Bean StubTransformer grpcCredentialsStubTransformer() { return CallCredentialsHelper.mappedCredentialsStubTransformer( Map.of( clientA, callCredentialsAC, clientB, callCredentialsB, clientC, callCredentialsAC)); }
注意: 如果你配置了
CallCredentials
bean,然后再使用StubTransformer
的话可能会造成冲突。
使用 (non-shaded)grpc-netty
当前项目目前支持 grpc-netty
和 grpc-netty-shaded
。 使用 grpc-netty-shaded
可以防止 grpc 跟 netty 版本的兼容性问题。
注意: 如果 grpc-netty-shaded
已经存在于 classpath 中, 那么将优先使用 shaded-netty
如果你使用的Maven,你可以使用如下的配置:
<dependency> <groupId>io.grpc</groupId> <artifactId>grpc-netty</artifactId> <version>${grpcVersion}</version> </dependency> <!-- For both --> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-spring-boot-starter</artifactId> <version>...</version> <exclusions> <exclusion> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> </exclusion> </exclusions> </dependency> <!-- For the server (only) --> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-server-spring-boot-starter</artifactId> <version>...</version> <exclusions> <exclusion> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> </exclusion> </exclusions> </dependency> <!-- For the client (only) --> <dependency> <groupId>net.devh</groupId> <artifactId>grpc-client-spring-boot-starter</artifactId> <version>...</version> <exclusions> <exclusion> <groupId>io.grpc</groupId> <artifactId>grpc-netty-shaded</artifactId> </exclusion> </exclusions> </dependency>
如果你使用的 Gradle,你可以使用如下的配置:
compile "io.grpc:grpc-netty:${grpcVersion}" compile 'net.devh:grpc-spring-boot-starter:...' exclude group: 'io.grpc', module: 'grpc-netty-shaded' // For both compile 'net.devh:grpc-client-spring-boot-starter:...' exclude group: 'io.grpc', module: 'grpc-netty-shaded' // For the client (only) compile 'net.devh:grpc-server-spring-boot-starter:...' exclude group: 'io.grpc', module: 'grpc-netty-shaded' // For the server (only)