GH-754 Add initial support for specifying grpc service

The newly added support allows one to actually specify which groc service to bootstrap in the event multiple services are available in the classpath

Resolves #754
This commit is contained in:
Oleg Zhurakousky
2021-10-11 20:46:43 +02:00
parent e5af50a356
commit 2b9a92fa18
6 changed files with 80 additions and 18 deletions

View File

@@ -34,6 +34,7 @@ message GrpcMessage {
As you can see it is a very generic structure which can support any type of data amd metadata you wish to exchange.
It alos defines a `MessagingService` allowing you to generate required stubs to support true plolyglot nature of gRPC.
```
service MessagingService {
rpc biStream(stream GrpcMessage) returns (stream GrpcMessage);
@@ -73,6 +74,7 @@ public static class SampleConfiguration {
```
After identifying this function via `spring.cloud.function.definition` property (see example [here](https://github.com/spring-cloud/spring-cloud-function/blob/ded02fec0a6d3d66b8ec00f99f28be2a4bbec668/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java)),
you can invoke it using utility method(s) provided in `GrpcUtils` class
```java
Message<byte[]> message = MessageBuilder.withPayload("\"hello gRPC\"".getBytes())
.setHeader("foo", "bar")
@@ -81,6 +83,7 @@ Message<byte[]> reply = GrpcUtils.requestReply(message);
```
You can also provide `spring.cloud.function.definition` property via `Message` headers, to support more dynamic cases.
```java
Message<byte[]> message = MessageBuilder.withPayload("\"hello gRPC\"".getBytes())
.setHeader("foo", "bar")
@@ -102,6 +105,7 @@ public static class SampleConfiguration {
```
After identifying this function via `spring.cloud.function.definition` property (see example [here](https://github.com/spring-cloud/spring-cloud-function/blob/ded02fec0a6d3d66b8ec00f99f28be2a4bbec668/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java)),
you can invoke it using utility method(s) provided in `GrpcUtils` class
```java
Message<byte[]> message = MessageBuilder.withPayload("\"hello gRPC\"".getBytes()).setHeader("foo", "bar").build();
@@ -114,6 +118,7 @@ List<Message<byte[]>> results = reply.collectList().block(Duration.ofSeconds(5))
You can see that gRPC stream is mapped to instance of `Flux` from [project reactor](https://projectreactor.io/)
Similarly to the _request/reply_ you can also provide `spring.cloud.function.definition` property via `Message` headers, to support more dynamic cases.
```java
Message<byte[]> message = MessageBuilder.withPayload("\"hello gRPC\"".getBytes())
.setHeader("foo", "bar")
@@ -143,6 +148,7 @@ public static class SampleConfiguration {
```
After identifying this function via `spring.cloud.function.definition` property (see example [here](https://github.com/spring-cloud/spring-cloud-function/blob/ded02fec0a6d3d66b8ec00f99f28be2a4bbec668/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java)),
you can invoke it using utility method(s) provided in `GrpcUtils` class
```java
List<Message<byte[]>> messages = new ArrayList<>();
messages.add(MessageBuilder.withPayload("\"Ricky\"".getBytes()).setHeader("foo", "bar")
@@ -175,6 +181,7 @@ public static class SampleConfiguration {
```
After identifying this function via `spring.cloud.function.definition` property (see example [here](https://github.com/spring-cloud/spring-cloud-function/blob/ded02fec0a6d3d66b8ec00f99f28be2a4bbec668/spring-cloud-function-grpc/src/test/java/org/springframework/cloud/function/grpc/GrpcInteractionTests.java)),
you can invoke it using utility method(s) provided in `GrpcUtils` class
```java
List<Message<byte[]>> messages = new ArrayList<>();
messages.add(MessageBuilder.withPayload("\"Ricky\"".getBytes()).setHeader("foo", "bar")
@@ -193,3 +200,34 @@ List<Message<byte[]>> results = clientResponseObserver.collectList().block(Durat
You can see that gRPC stream is mapped to instance of `Flux` from [project reactor](https://projectreactor.io/)
Unlike the _request/reply_ and _server-side streaming_, you can ONLY pass function definition via property or environment variable.
#### Pluggable protobuf extension
While the core data object and its corresponding schema <<Core-Data-and-Service>> are modeled after Spring Message and can represent
virtually any object, there are times when you may want to plug-in your own protobuf services.
Spring Cloud Function provides such support by allowing you to develop extensions, which once exist could be enabled by simply
including its dependency in the POM. Such extensions are just another spring-boot project that has dependency on `spring-cloud-function-grpc`
```xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-grpc</artifactId>
</dependency>
```
It must also contain 3 classes; 1) Its configuration class, 2) Type converter for the actual protobuf 'message'and 3) Service handler
where you would normally implement your handling functionality. However instead of implementing full functionality you can model your service
after MessagingService provided by us and if you do you can rely on the existing implementation of the core interaction models provided by gRPC
In fact Spring Cloud Function provides one of such extensions to support [Cloud Events](https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-adapters/spring-cloud-function-grpc-cloudevent-ext) proto, so you can model yours after it.
#### Multiple services on classpath
With the protobuf extension mentioned in the previous section you may very well end up with several services on the classpath.
By default each available service will be enabled. However, if your intention is to only use one, you can specify which one by providing
its class name via `spring.cloud.function.grpc.service-class-name` property:
```
--spring.cloud.function.grpc.service-class-name=org.springframework.cloud.function.grpc.ce.CloudEventHandler
```