Add stream (kafka, Rabbit) and Rsocket examples for Cloud Event

This commit is contained in:
Oleg Zhurakousky
2020-12-18 16:33:48 +01:00
parent 17d5d4b727
commit 8ece3d3083
41 changed files with 2277 additions and 163 deletions

View File

@@ -1,77 +1,29 @@
## Examples of Cloud Events with Spring
## Examples of Cloud Events with Spring via HTTP
### Introduction
The current example uses spring-cloud-function framework as its core which allows users to only worry about functional aspects of
their requirement while taking care-off non-functional aspects. For more information on Spring Cloud Function please visit
our https://spring.io/projects/spring-cloud-function[project page].
The example consists of a class https://github.com/spring-cloud/spring-cloud-function/blob/master/spring-cloud-function-samples/function-sample-cloudevent/src/main/java/io/spring/cloudevent/CloudeventDemoApplication.java[CloudeventDemoApplication]
which contains a set of function beans of different type signatures which you can interact with following instructions below.
It also provides necessary dependencies and instructions to demonstrate several distinct invocation models:
- _Direct function invocation_
- _Function as a REST endpoint_
- _Function as message handler (e.g., Kafka, RabbitMQ etc)_
- _Function invocation via RSocket_
The POM file defines all the necessary dependency in a segregated way, so you can choose the one you're interested in by commenting in/out dependencies
that fit your scenario (e.g., Streaming vs. REST, ect_
### Direct function invocation
By looking up user declared functions in `FunctionCatalog` you can interact (i.e., for testing purposes) with functions directly
while enjoying all the features of _spring-cloud-function_ such as transparent type conversion, function composition and more.
[source, java]
----
Message<String> binaryCloudEventMessage = MessageBuilder
.withPayload("{\"releaseDate\":\"24-03-2004\", \"releaseName\":\"Spring Framework\", \"version\":\"1.0\"}")
.setHeader("ce-specversion", "1.0")
.setHeader("ce-type", "com.example.springevent")
.setHeader("ce-source", "spring.io/spring-event")
.setHeader("ce-id", "123-456-9876-09")
.build();
Function<Message<String>, String> asPojoMessage = catalog.lookup("asPOJOMessage");
System.out.println(asPojoMessage.apply(binaryCloudEventMessage));
----
The test case link:src/test/java/io/spring/cloudevent/CloudeventDemoApplicationFunctionTests.java[CloudeventDemoApplicationFunctionTests]
provides a good example on how to accomplish this.
### Function as a REST endpoint
The example consists of a Spring boot configuration class
https://github.com/spring-cloud/spring-cloud-function/blob/master/spring-cloud-function-samples/function-sample-cloudevent/src/main/java/io/spring/cloudevent/DemoApplication.java[DemoApplication]
which contains a sample function which you can interact with following via HTTP.
Given that SCF allows function to be exposed as REST endpoints, you can post cloud event to any of the
functions by using function name as path (e.g., `localhost:8080/<function_name>`).
Just add this to your dependency (or in your case simply un-comment)
[source, xml]
----
<!-- REST - only needed if you intend to invoke via HTTP -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-function-web</artifactId>
<version>3.1.0-SNAPSHOT</version>
</dependency>
<!-- end REST -->
----
Here is an example of curl command posting a cloud event in binary-mode:
[source, text]
----
curl -w'\n' localhost:8080/asPOJO \
curl -w'\n' localhost:8080/hire \
-H "ce-id: 0001" \
-H "ce-specversion: 1.0" \
-H "ce-type: com.example.springevent" \
-H "ce-type: hire" \
-H "ce-source: spring.io/spring-event" \
-H "Content-Type: application/json" \
-H "ce-id: 0001" \
-d '{"releaseDate":"24-03-2004", "releaseName":"Spring Framework", "version":"1.0"}'
-d '{"firstName":"John", "lastName":"Doe"}' -i
----
And here is an example of curl command posting a cloud event in structured-mode:
@@ -87,85 +39,9 @@ curl -w'\n' localhost:8080/asString \
"id" : "A234-1234-1234",
"datacontenttype" : "application/json",
"data" : {
"version" : "1.0",
"releaseName" : "Spring Framework",
"releaseDate" : "24-03-2004"
"firstName" : "John",
"lastName" : "Doe"
}
}'
----
Feel free to change the function you're invoking by changing URI path (e.g., `localhost:8080/asString` to `localhost:8080/consumeAndProduceCloudEventAsPojoToPojo`).
### Function as message handler (e.g., Kafka, RabbitMQ etc)
Streaming support for Apache Kafka and RabbitMQ is provided via https://spring.io/projects/spring-cloud-stream[Spring Cloud Stream] framework.
In fact we're only mentioning Apache Kafka and RabbitMQ here as an example.
Streaming support is automatically provided for any existing binders (e.g., Solace, Google PubSub, Amazon Kinesis and many more).
Please see project page for for additional details on available binders.
Binders are components of Spring Cloud Stream responsible to bind user code (e.g., java function) to message broker destinations, so execution
is triggered by messages posted to the broker destination and results of execution are sent back to the broker destinations. Binders also provide
support for _consumer groups_, _partitioning_ and many other features. For more information on Spring Cloud Stream, Binders and available features
please visit our https://docs.spring.io/spring-cloud-stream/docs/3.1.0-SNAPSHOT/reference/html/[documentation page].
*RabbitMQ*
By simply declaring the following dependency
[source, xml]
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-rabbit</artifactId>
<version>3.1.0-SNAPSHOT</version>
</dependency>
----
. . . any function can now act as message handler bound to RabitMQ message broker. All you need to do is identify which function you intend to bind
by identifying it via `spring.cloud.function.definition` property.
[source, text]
----
--spring.cloud.function.definition=asPOJOMessage
----
See link:src/main/resources/application.properties[application.properties] for more details.
Assuming RabbitMQ broker is running on localhost:default_port, start the application and navigate to
http://localhost:15672/#/exchanges[RabbitMQ Dashboard]. Select `asPOJOMessage-in-0` exchange and:
_...post a binary-mode message by filling all the required Cloud Events headers and posting `data` element as payload (see the screenshot below)._
image::images\rabbit-send-binary.png[binary,700,700]
_...post a structured-mode message by filling `contentType` header to the value of `application/cloudevents+json` while providing the
entire structure of Cloud Event message as payload (see the screenshot below)._
[source, json]
----
{
"specversion" : "1.0",
"type" : "org.springframework",
"source" : "https://spring.io/",
"id" : "A234-1234-1234",
"datacontenttype" : "application/json",
"data" : {
"version" : "1.0",
"releaseName" : "Spring Framework",
"releaseDate" : "24-03-2004"
}
}
----
image::images\rabbit-send-structured.png[structured,700,700]
You can follow similar approach with Apache Kafka or any other binder. All you need is bring a required binder dependency.
For example for Apache Kafka
[source, xml]
----
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream-binder-kafka</artifactId>
<version>3.1.0-SNAPSHOT</version>
</dependency>
----
### Function invocation via RSocket
TBD