Spring Boot Lambda Implementation

Spring Boot Lambda Implementation

Creating a Spring Boot Lambda on AWS

Learn how to build and deploy a simple spring boot based AWS lambda and then automate its deployment with Terraform.

full course
  1. Spring Boot Lambda Prerequisites
  2. Spring Boot Lambda Implementation
  3. Spring Boot Lambda API Implementation
  4. Terraform Setup and First Install
  5. Terraform Centralized State Management
  6. Automated Terraform Deploy Using Github Actions
  7. Confirming the Continuous Deployment Pipeline

Now we’re going to add some code. I’m going to follow my ports and adapters method of building a DTO and value object that I’ve used previously. Yes, its a bit of overkill for this project (especially a hello world example), but if you’re using this course as a springboard to build another project, I think its a good habit to get into. Especially since lambda functional code supplied by spring introduces some code you may not want in your service layer.

Build the Service Layer

create a class in a new service package for the service:

package com.bullyrooks.helloworldlambda.service;

import com.bullyrooks.helloworldlambda.service.vo.HelloWorld;
import org.springframework.stereotype.Component;

@Component
public class HelloWorldService {

    public HelloWorld helloWorld(String name) {
        return HelloWorld.builder()
                .response("Hello, " + name)
                .build();
    }
}

Create a new value object to handle the response in a new package service/vo

package com.bullyrooks.helloworldlambda.service.vo;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class HelloWorld {
    private String response;
}

We’ll need to import some libraries to support the function features, so add these libraries to your pom.xml

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.4.5</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
...
	<properties>
		<java.version>11</java.version>
		<aws-lambda-java-events.version>3.1.0</aws-lambda-java-events.version>
		<aws-lambda-java-core.version>1.2.0</aws-lambda-java-core.version>
		<spring-cloud.version>Hoxton.SR6</spring-cloud.version>
		<wrapper.version>1.0.11.RELEASE</wrapper.version>
	</properties>

...

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>org.springframework.cloud</groupId>
				<artifactId>spring-cloud-dependencies</artifactId>
				<version>${spring-cloud.version}</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

...

		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-function-adapter-aws</artifactId>
		</dependency>
		<dependency>
			<groupId>com.amazonaws</groupId>
			<artifactId>aws-lambda-java-events</artifactId>
			<version>${aws-lambda-java-events.version}</version>
		</dependency>
		<dependency>
			<groupId>com.amazonaws</groupId>
			<artifactId>aws-lambda-java-core</artifactId>
			<version>${aws-lambda-java-core.version}</version>
		</dependency>


...


			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<version>3.2.0</version>

				<configuration>
					<archive>
						<manifest>
							<mainClass>com.bullyrooks.helloworldlambda.HelloworldLambdaApplication</mainClass>
						</manifest>
					</archive>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-deploy-plugin</artifactId>
				<configuration>
					<skip>true</skip>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<dependencies>
					<dependency>
						<groupId>org.springframework.boot.experimental</groupId>
						<artifactId>spring-boot-thin-layout</artifactId>
						<version>${wrapper.version}</version>
					</dependency>
				</dependencies>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-shade-plugin</artifactId>
				<version>3.2.4</version>
				<configuration>
					<createDependencyReducedPom>false</createDependencyReducedPom>
					<shadedArtifactAttached>true</shadedArtifactAttached>
					<shadedClassifierName>aws</shadedClassifierName>
				</configuration>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>shade</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
		</plugins>
		<finalName>${project.name}</finalName>

First off, I’m downgrading the version of spring boot parent. I thought I had some trouble with java 11, the spring boot parent and the version of the spring cloud that I was bringing in and this combination worked. Second, I’m setting up the properties for the versions of the dependencies I’m bringing in. Next, setting up spring cloud dependency management because I have one spring cloud dependency. Also, adding a bunch of new dependencies.

The plugins need more explanation:

  • maven jar plugin is identifying the spring boot application class so that the command line startup can find it quickly
  • spring boot maven is adding a thin layout to try and keep the size of the jar down
  • maven shade plugin identifies our dependencies and pulls them into an uber jar which allows the .jar to operate without any jars on (external) classpath

We’re going to want uber jars (that contain all of their dependencies) that are very small (because this helps with keeping storage costs down and improves transfer speeds).

Add the Function

First, create a new package function and add this class:

@Component
public class HelloWorldFunction implements Function<String, String> {

    @Autowired
    HelloWorldService helloWorldService;

    @Override
    public String apply(String input) {
        return helloWorldService.helloWorld(input).getResponse();
    }
}

That’s all you need. We’re going to use some spring magic to wire this up. But first, rebuild so we can deploy

$ mvn clean package
...
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  8.505 s
[INFO] Finished at: 
[INFO] ------------------------------------------------------------------------

Create the Lambda

Now log into aws console and navigate to the Lambda section

Click Create Function

Choose Author from scratch

Name the lambda and choose the java 11 runtime

In code source, click upload from

Choose the helloworld-lambda-0.0.1-SNAPSHOT-aws.jar which is the shaded uber jar (which has also been slimmed down).

Edit the runtime settings to use the built in aws function invoker

Use the org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest handler

Finally, go to the configuration tab, select environment variables and add an environment variable for a key of FUNCTION_NAME and a value of your function class HelloWorldFunction

Test the Lambda

Go to the Test tab, use the hello-world template and add a test that looks like this:

and hit test. You should see a succeeded output:

Commit and Finish

We’ve got a working lambda! Its not very useful at this point though. We’ll add an API to it next.

Let’s commit and merge.

$ git status
On branch function
Your branch is up to date with 'origin/function'.

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git restore <file>..." to discard changes in working directory)
        modified:   pom.xml
        modified:   src/main/java/com/bullyrooks/helloworldlambda/HelloworldLambdaApplication.java

Untracked files:
  (use "git add <file>..." to include in what will be committed)
        src/main/java/com/bullyrooks/helloworldlambda/function/

no changes added to commit (use "git add" and/or "git commit -a")

$ git add .

$ git commit -m "working lambda"
[function ced0de0] working lambda
 3 files changed, 144 insertions(+), 86 deletions(-)
 rewrite pom.xml (97%)
 create mode 100644 src/main/java/com/bullyrooks/helloworldlambda/function/HelloWorldFunction.java


$ git push
Logon failed, use ctrl+c to cancel basic credential prompt.
Username for 'https://github.com': bullyrooks
Password for 'https://[email protected]':
Enumerating objects: 21, done.
Counting objects: 100% (21/21), done.
Delta compression using up to 4 threads
Compressing objects: 100% (9/9), done.
Writing objects: 100% (12/12), 2.12 KiB | 2.12 MiB/s, done.
Total 12 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (2/2), completed with 2 local objects.
To https://github.com/bullyrooks/helloworld-lambda.git
   0420e4f..ced0de0  function -> function

$ git checkout main

$ git merge function

$ git push

0 comments on “Spring Boot Lambda ImplementationAdd yours →

Leave a Reply

Your email address will not be published.