Spring Functions

 

Spring Cloud Function is a project by the Spring team at Pivotal that provides a way to build software around units of work called functions which can be deployed in a serverless platform or a webserver.

A function can produce, consume, route, filter, aggregate or organize messages coming from different sources and pushed to different destination using HTTP requests or events from brokers such as Kafka, RabbitMQ.

Developers can implement functions using imperative or non-blocking reactive programming (using Spring WebFlux library). A Spring function project can be packaged into a jar and can be deployed in a serverless or server architecture with the provided dependencies and configuration.

The project abstracts most configuration to provide the developer just the necessary to develop the business code regardless of the underlying infrastructure it will be deployed on.

The same function code can be deployed as a RESTful service by providing autoconfiguration with Spring boot or become a streaming application with spring cloud stream dependencies.

The function can also be packaged with a vendor specific serverless platform adapter to be deployed on existing serverless platforms such as AWS Lambda, Azure, Apache OpenWhisk or Oracle Fn.

The clear separation between the business code and the adapters libraries do not couple the application code to any cloud platform vendors.

 

Java functional interface support

The framework uses 3 functional interfaces provided since java 8 to describe a function: Supplier, Function and Consumer. The choice to use these interfaces has always been in the philosophy of Spring to decouple the framework code from the java code. They permit developers to easily onboard a project since they are familiar with these functional interfaces.

In a Spring function project, a method annotated with a @Bean annotation and containing these java interfaces are automatically detected and declared as a spring function.

The name of the function is by default the name of the method. The functions detected are placed inside an internal registry called CatalogFunction so they can be retrieved programmatically just like instance of beans in an ApplicationContext.

Here is an example of 3 functions named “generate”, “addBar” and “printMessage” using the 3 functional interfaces.

 

Supplier<O>

Represents the source of the Stream, it can be reactive with the use of the class Flux or imperative.

Example

Here is a code example of an imperative method generating a single Message containing a payload of type String.

Note: Message is a generic class type from the spring messaging library, it provides some useful functionality such as routing and input enrichment

 

Function<I,O>

A function taking in an input and producing an output can be implemented in a reactive style with Flux/Mono (reactive stream library) or in imperative style where the function is invoked on each event

Example

Receives a Message containing a payload String (ex: “foo”) and outputs a new Message with a payload String “foobar”.

Consumer<I>

A consumer takes an input and does not return an output. The return type is void.

Example

Receive a String and print the payload

Message interface

The Message interface Message<T> provides a generic message representation with headers and body, it is used to convey payload objects with headers. Spring Function provides multiple message converters to convert the incoming data to the generic type declared in the Message. The type converters include JSON, String, Byte array, or a custom type (with the implementation of a custom converter).

Example:

A function’s input type Message<User> can receive a json string such as {“name”:”John”}, detect the input type as a JSON and map values to the User object using an JsonConverter.

 

This interface is part of the spring-messaging library which is used in other Spring projects (Spring integration, Spring cloud Stream)

 

Function composition

A declarative function composition is a feature that provides a way to compose multiple function into one using a pipe “|” delimiter via spring.cloud.function.definition property

Function router

Routing a message can be configured in 3 ways:

  • Header “cloud.function.definition” containing the name of the function
  • Header “spring.cloud.function.routing-expression” containing SpEl expression to resolve the name
  • A Function returning a MessageRoutingCallback containing the name of the function

 

Example of a Messaging RoutingCallback returning the value of a header “func_name”:

 

 

 

 

The router Function retrieves the function name in the “func_name” header to route the message:

 

Function arity

Function can take in a multiple input and/or return multiple outputs with the use of Spring’s project reactor Tuple classes.  A function can input or output a maximum of 8 streams (In project Reactor, there is no class above Tuple8)

Example of a 2 input stream and one single output stream. In the merged output stream, all the strings are uppercased.

 

 

 

 

Multiple input/output Function can be used when there is need to treat, categorize and organize large amounts of data. A use case can be in a big data context where a flow of unorganized data can be organized in multiple data stores.

 

Standalone Webapplication or Standalone Stream application

Spring functions can be wrapped inside a web application or a Stream application. The configuration is made by Spring Autoconfiguration based on dependencies included in the class path.

Include spring-cloud-function-web module into a Spring boot web application to convert the Spring function into a web application with the function accessible through different HTTP methods.

Example: POST “/addBar” with text “foo”

 

Note: the URL called is the name of the method function. This url naming may seem unconventional to the naming of RESTful resources, this is because the function is not a resource but an ‘business’ operation that does not persist a resource. In the version currently tested, it is not possible to rename Spring function URL in the framework.

Note 2: During our tests, we noticed http headers passed in the query cannot be received by method function, this may be an issue for some use cases.

The stream Spring function “addBar” can be converted into a Streaming application with the use of the spring-cloud-stream project’s configuration. Messages can be received or sent to brokers such as Kafka RabbitMQ, Spring function provide the adapters to communicate.

 

Deploy a packaged function

 

Spring function project provides a way for a Spring boot application to deploy an external package jar file containing all the spring functions inside an isolated class loader and expose the Spring function to deployer. To enable this feature, the springboot project must include the spring-function-deployer library.

The deployment jar can contain different types of input-output adapter and can be used to connect to functions from the external jar. Different adapters can be loaded at runtime and changed without impacting the external jar.

 

 

 

 

 

 

 

There are multiple ways to deploy the spring function jars such as exploded archive or set of jar files. We invite you to have a look at the official documentation for further information.

This kind of feature is often built in serverless platforms (AWS, Azure,.. ) . This deployer could be used as a building block for a function invoker and we can imagine it can be possible to build a FAAS (Function as a service) platform with this tool.

 

Testing functional applications

The spring function application can be tested just as a classic SpringBoot application using the @SpringBootTest annotation. The application is wrapped inside a HTTP Server and Rest services are exposed.

 

 

 

 

 

 

Spring Function provides an @FunctionnalSpringBootTest annotation which inherits @SpringBootTest and provides the detection of Spring function that are automatically registered in the CatalogFunction context.

The function can be tested as non-HTTP based application and directly called in a unit test.

 

 

 

 

 

 

Conclusion

We have seen that Spring function enables us to build enterprise integrated applications with multiple functions organized in different forms to follow well known enterprise messaging patterns.

The configuration is lightweight, and the framework enables easy switching between adaptors (RESTful webservice, RabbitMQ adaptor, Kafka, Serverless platform adapter…) in a decouple manner and facilitates the developer in many ways with its autoconfiguration.

The deployer library provided enables more possibilities such as invoking function from another Spring boot application.

The project has a solid foundation but during our tests there may be some limitations on some features, such as functions are unable to receive http headers when configured in standalone web application, but it may change in future versions.

Read also

- - -

Quarkus

Quarkus est un framework Java open source permettant le développement …