Spring Cloud Functions are yet another interesting option for Java developers when building serverless applications. You have already seen how to build and run applications for Red Hat OpenShift Serverless using Quarkus, but in this article, we talk about how to use Spring Cloud Functions and walk you through those steps. These steps are similar to running any other Spring Boot application with OpenShift Serverless. One of the benefits of building an open hybrid serverless platform is giving developers a choice of programming languages, tools, frameworks, and portability across any environment to run serverless applications. Beyond that, you want to ensure that the developer experience and overall workflow is intuitive and practical, which is what you will learn here.
If you are interested in just watching the steps performed in this article you can watch the recording on YouTube.
- Java Development Tool Kit (JDK 8+)
- OpenShift 4.3+
- OpenShift Serverless 1.7+
Generate the Spring Cloud Functions project
One of the easiest ways to generate a Spring project is using
curl to access
start.spring.io and that's exactly how we will start our project:
This will generate and download a project inside the
Implement your first function
We will implement a quick and dirty Google Translator wrapper. In order to create functions using Spring Cloud Functions, you need a method with the
@Bean annotation that can follow any of the functional interfaces from
java.util.function such as
Function. For more details about how Spring Cloud Functions work please read the documentation, but for this example just copy and paste the following method to your DemoApplication.java file:
Test your function locally
Since Spring Cloud Functions are just Spring Boot apps, you can implement unit tests just like any other Java application using JUnit, Mockito, or whatever you would like. You can also run the application locally, using
gradle bootRun or
mvn spring-boot:run, which is useful for validating the application iteratively before running inside a container. Make sure you have fixed all Java imports and then start the application locally using:
Every function will be mapped to an endpoint that can be accessed as follows:
Concretely, for our translate function, you can access the endpoint using the following:
curl we post a word or a phrase and it gets translated to Spanish. You can parse the output and format it properly, but to keep this short I'll leave that as an exercise for the reader. May Jackson and JSON be your friends.
Building a container using Jib
So far we have built a Spring application and executed it locally but it's time to containerize the application. There are many ways to execute this step but I've decided to stick to well-known tools used by the Java community, so I'll use
Jib and add it as a plugin to my Gradle project.
build.gradle file and append this line
id 'com.google.cloud.tools.jib' version "2.4.0" to your plugins section. It should look like this:
After you have the jib plugin on your Gradle project, build a container for the project using the following command:
gradle build jib --image=<your_container_registry>/demo-app:v1
On my machine this is what it looks like:
This generated a container for your project and automatically pushed it to the container registry. If you are new to Linux containers and container registries please read this post to get a practical introduction to the topic.
Deploy to OpenShift Serverless
With the container built you can now deploy the application using the Knative CLI,
OpenShift Serverless will do the heavy lifting of creating a Kubernetes deployment, a route, SSL configuration (using your cluster's configuration), and auto-scaling configuration based on the number of requests. For more details about OpenShift Serverless, please check out the product documentation.
The above code will auto-scale the application down (to zero) after six seconds without a new request.
Try it again using the URL from the service running in OpenShift:
Adding a new function that can handle a JSON document
When creating REST APIs it is very common to send and receive JSON documents and you can very easily add a function that takes a JSON message instead of a String.
The data model
Create a new
UserReview.java file with the following content:
We will use this class to marshal and unmarshal the JSON objects being sent or received by our API. Create a
review.json file with the content below. This will be the input of our new
The function code
This will be very similar to the previous function we created, it's just another method with the
@Bean annotation and using our POJO class as input and output.
Posting a JSON file
We will continue using
curl as our client here and specify a path to the
review.json file created in the previous step. Start the application again using
gradle bootRunthen post a json file to the API:
As you can see, the function now accepts a JSON document and translates the user comment to Spanish. You can experiment with a declarative function composition way to implement this if that's your cup of tea, but I'm keeping this simple for now.
Building your new container
Same steps as before but using a
v2 tag, build a new version of the container:
$ gradle jib --image=<your_container_registry>/demo-app:v2
Updating the deployed application to include the new function
Now we are going to use another interesting feature of OpenShift Serverless, we will deploy a new version of the application but with a different URL, that way current clients of this API won't even know about this new functionality until we decide to send traffic to it:
This can be achieved by using tags. In this example, I'm tagging a particular revision
@latest with a
preview value that will be appended to the service URL. Also note, that I'm setting 100% of traffic to the previous revision
translator-v1, which means no traffic will be sent to the new version being deployed. This is also called a "dark launch," where a new version of my application is available in a production environment but not necessarily receiving any requests unless someone knows which URL to use.
After validation is complete you can decide to gradually send traffic using canary or blue/green deployment models. There is a step-by-step lab about how to implement those models on https://developers.redhat.com/node/269571
Now you can execute the same curl command as before but this time adding the
You can easily build and deploy a Spring Cloud Functions application using OpenShift Serverless. The workflow feels natural for a Java developer and you can even build the container using a Gradle (or Maven) plugin such as Jib.
Using OpenShift Serverless you can also deploy multiple versions of the application and perform a dark launch, blue/green, or canary deployment with no sweat. The OpenShift developer console makes it even easier to visualize traffic route information and the overall topology of your application.
For more details, check the OpenShift Serverless page.