How to Deploy a Spring Cloud Function on AWS Lambda
Want to gain a first experience with Spring Cloud Function and deploy it at AWS Lambda? Check out this hands-on tutorial.
Join the DZone community and get the full member experience.Join For Free
In this post, we will create a Spring Cloud Function and create some unit tests for it. We will do so by creating a function with Bean definition and with the functional style. At the end, we will deploy the function on AWS Lambda.
Spring Cloud Function allows us to implement business logic via functions and we can create a Spring Boot application just as we are used to. You can run the function locally but of course it is the intention to run it at some serverless provider. We will show both cases in this post and will use AWS Lambda as serverless provider. You will need to create an AWS account first. See our previous blog How to Deploy a Spring Boot App to AWS Elastic Beanstalk how to create an AWS account. The sources of the examples we are using, can be found at GitHub.
Detailed information about Spring Cloud Function is available in the official documentation.
2. Create Function With Bean Definition
We will create a function in the traditional style with Bean definition. Our function will accept a
String and verify whether the word cloud is present in the provided
String. The function returns true if present, otherwise false. A very basic function, but this will allow us to focus on some basic principles instead of a complex piece of business logic. The source code is available in branch feature/function-with-bean-definition.
Go to Spring Initialzr, leave the defaults and add dependency Spring Cloud Function. Also, checkout the Explore button in Spring Initializr, it is really awesome! After importing the project in our favourite IDE, we create the function.
This is quite simple, isn’t it? Just a basic Spring Boot application with a single Bean. Now, in order to be able to invoke the function via a http endpoint, we only need to add the
spring-cloud-starter-function-web dependency to our
After doing so, run the application:
Verify the function for a true result:
Verify the function for a false result:
Instead of testing the function manually, we can also create some unit tests for it. Nothing new when you are familiar with creating unit tests for a Spring Boot application.
Build the application together with running the tests:
3. Rewrite Function to Functional Style
Now that we have created the function with traditional Bean definition style, we can now rewrite the application by using the functional Bean definition style. The code is available in branch feature/function-with-functional-style. Reason for choosing the functional style above the traditional style is the major improvement in startup time. In our example, the startup time with traditional Bean style is about 1s and with the functional style about 250ms. We need to change the following in order to rewrite the function:
@SpringBootConfiguration, we do not enable Spring Boot autoconfiguration with this, but mark the class as an entry point;
- The main class becomes a
FunctionalSpringApplicationwhich is a subclass of
- We remove the
@Beanannotation and implement the
initializemethod and register the bean(s) over here.
The end result is:
Running the application will cause the following error:
It appears that the
FunctionalSpringApplication approach is tightly coupled to WebFlux. See also the GitHub issues 459 and 467. The issue is seen as an enhancement because it apparantely never worked. For now, the solution is to use
spring-cloud-starter-function-webflux instead of
spring-cloud-starter-function-web. Change the
Running our tests will fail now:
First of all, we need to use the
FunctionalSpringBootTest annotation. Secondly, because we are now using the WebFlux dependency, we need to rewrite the tests in order to use
WebClient instead of
MockMvc. It is quite similar as
MockMvc as you can see:
4. Deploy to AWS Lambda
Now that we have create the function, it is time to deploy the function to AWS Lambda. We will use the official documentation and the sample app in order to make the changes to our own application. The sample app is in traditional form, so let’s see whether this also works for the functional style implementation.
We need to make the following changes to the
- Add the dependencies
- Set the scope of dependency
test. We do not need this dependency for deployment to AWS Lambda, but we do need it for our unit tests.
- Disable the deploy phase in the
- Add a dependency on
spring-boot-maven-plugin. More information about the thin layout can be found here. Basically, it will create a small and executable jar file.
- Add the
maven-shade-plugin. The Maven Shade Plugin will by default replace the project’s main artifact with the shaded artifact. If both the original and the shaded artifact should be installed/deployed to the repository, one can configure the plugin to attach the shaded artifact as a secondary artifact by means of the configuration properties
shadedClassifierName. The flag
createDependencyReducedPomis by default true and will generate a simplified version of the
pom. But we do not need this, so we set it to
false. A complete overview of the parameters can be found here.
The changes to the
pom are (code is present in the master branch):
Create the jar files:
This will create the two jars. Some warnings are raised, but we will ignore them.
We will create the function in AWS by means of the AWS Management Console. It is also possible to do so by means of the AWS CLI.
Login to the AWS Management Console and search for the AWS Lambda service.
In the AWS Lambda page, click the Create function button.
Give the function a name and select Java 11 (Corretto) as runtime and click the Create function button at the bottom right corner.
Navigate to the Function code section and choose Upload a .zip or .jar file from the Actions menu.
Select the aws jar file located in your target directory and click the Save button.
Navigate to the Basic settings section and click the Edit button.
org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest as Handler and click the Save button.
In order to test the function, we will create two test events. Go to the right top corner and select Configure test events.
Create a SuccessEvent and a FailEvent.
When running the Test SuccessEvent, the following error occurs:
Remember that we used the functional style and the samples we found were all with the traditional style. So, let’s return to the bean definition style again (branch feature/aws-function-bean-defintion) and run:
Deploy the aws jar to AWS Lambda and invoke the SuccessEvent again. The result is now successful.
Do the same with FailEvent and this is also successful.
According to a Spring blog, the functional style should work without any problem, but it gives us an error.
We could not find out what caused the problem and therefore posted a question on StackOverflow.
At the end, do not forget to delete your function again in order to minimize any costs.
Creating a function with Spring Cloud Function is fairly easy. It is a great advantage that you can use your experience with Spring Boot in order to develop serverless functions. Deploying the function to AWS Lambda is also fairly easy but we encountered a problem when using the functional style for developing the function. The traditional style worked out-of-the-box.
Published at DZone with permission of Gunter Rotsaert, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.