AWS Developer Tools Blog

Bootstrapping a Java Lambda application with minimal AWS Java SDK startup time using Maven

We’re excited to share a new Maven Archetype for Java Lambda applications that we released recently and show you how to start building Java Lambda applications quickly, using this archetype. With the new archetype, customers can easily bootstrap a Java Lambda project configured with the AWS SDK for Java 2.x as a dependency and SAM template to deploy it to AWS Lambda. In addition, the generated application has SDK best-practices incorporated to achieve minimal SDK startup time. In this blog post, we will generate an application, build it, and deploy it to Lambda.

Prerequisites

To use this tutorial, you need to have the following software installed. This post assumes you have some familiarity with Java programming and the Maven build system.
Java 8
Apache Maven
AWS CLI
SAM CLI

Generating the application

To generate a project, open a terminal (command line) window and run mvn archetype:generate command. There are two modes you can choose: interactive mode and batch mode.

  • Interactive mode

In interactive mode, you’ll be prompted to provide required properties, one at a time.

mvn archetype:generate \
-DarchetypeGroupId=software.amazon.awssdk \
-DarchetypeArtifactId=archetype-lambda \
-DarchetypeVersion=2.15.79
  • Batch mode

In batch mode, you need to provide all required properties at once. Below is the list of the required properties and you can check out all available options here.
Required Properties

    • service: the service client to be used in the lambda function, eg: s3, dynamodb.
    • region: the region to be set for the SDK client in the application
    • groupId: the Maven group ID of the application
    • artifactId: the Maven artifact ID of you application

The command below demonstrates creating an application that uses S3 SDK client configured with us-west-2 region. The artifactId of the project is test-project and the groupId is com.amazon.test.

mvn archetype:generate \
    -DarchetypeGroupId=software.amazon.awssdk \
    -DarchetypeArtifactId=archetype-lambda \
    -DarchetypeVersion=2.15.79 \
    -DgroupId=com.amazon.test \
    -DartifactId=test-project \
    -Dservice=s3  \
    -Dregion=us-west-2 \
    -DinteractiveMode=false

The output will be something like this:

[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: archetype-lambda:2.11.4
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: com.amazon.test
[INFO] Parameter: artifactId, Value: test-project
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: package, Value: com.amazon.test
[INFO] Parameter: packageInPathFormat, Value: com/amazon/test
[INFO] Parameter: httpClient, Value: url-connection-client
[INFO] Parameter: handlerClassName, Value: App
[INFO] Parameter: groupId, Value: com.amazon.test
[INFO] Parameter: service, Value: s3
[INFO] Parameter: version, Value: 1.0-SNAPSHOT
[INFO] Parameter: nettyOpenSslVersion, Value: 2.0.29.Final
[INFO] Parameter: javaSdkVersion, Value: 2.11.4
[INFO] Parameter: region, Value: us-west-2
[INFO] Parameter: package, Value: com.amazon.test
[INFO] Parameter: artifactId, Value: test-project
[INFO] Project created from Archetype in dir: /private/tmp/test-project
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 19.724 s
[INFO] Finished at: 2020-03-30T16:10:12-07:00
[INFO] Final Memory: 20M/315M
[INFO] ------------------------------------------------------------------------

When the archetype:generate goal completes, you will have a Maven project with a dependency on the AWS Java SD 2.x and SDK client construction code with optimized configuration for Lambda. Below is the structure of the generated project from the command above.

test-project
├── README.md
├── pom.xml
├── src
│   ├── main
│   │   └── java
│   │       └── com
│   │           └── amazon
│   │               └── test
│   │                   ├── App.java
│   │                   └── DependencyFactory.java
│   └── test
│       └── java
│           └── com
│               └── amazon
│                   └── test
│                       └── AppTest.java
└── template.yaml

The App.java class is the entry point for the Lambda function. The DependencyFactory.java class contains the configured SDK client. The template.yaml is a SAM template file where you can configure different properties of your lambda function, such as memory size and timeout.

Building the application

To build the application, run the following commands:

# Go to project directory created. 
# The name should be the same as the artifactId provided
cd test-project

# Build the application
mvn clean install

Once it completes, it will generate a single JAR in the target folder. The JAR file contains the compiled function code and all of its dependencies, and it can be deployed to Lambda later.
The output will be something like the following

[INFO] Replacing /private/tmp/test-project/target/test-project.jar with /private/tmp/test-project/target/test-project-1.0-SNAPSHOT-shaded.jar
[INFO]
[INFO] --- maven-install-plugin:2.4:install (default-install) @ test-project ---
[INFO] Installing /private/tmp/test-project/target/test-project-1.0-SNAPSHOT.jar to /Users/zoewang/.m2/repository/com/amazon/test/test-project/1.0-SNAPSHOT/test-project-1.0-SNAPSHOT.jar
[INFO] Installing /private/tmp/test-project/pom.xml to /Users/zoewang/.m2/repository/com/amazon/test/test-project/1.0-SNAPSHOT/test-project-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.214 s
[INFO] Finished at: 2020-03-30T16:10:44-07:00
[INFO] Final Memory: 31M/253M

To test the generated Lambda function locally with SAM CLI , you can run the following command.

sam local invoke

This command executes the Lambda function locally and is useful to verify that the function works before deploying it to AWS Lambda. The output looks like this

END RequestId: cbdf9d00-983b-1c9a-1380-6785a57af655
REPORT RequestId: cbdf9d00-983b-1c9a-1380-6785a57af655    Init Duration: 3930.21 ms    Duration: 89.91 ms    Billed Duration: 100 ms    Memory Size: 512 MB    Max Memory Used: 74 MB

{}

Deployment

To deploy the application, you can run the following command. You can learn more about sam deploy here.

sam deploy --guided

The guided prompts will first ask you to provide configurations regarding the deployment. The output will be something like this

$ test-project sam deploy --guided
Configuring SAM deploy
======================

    Looking for samconfig.toml :  Not found

    Setting default arguments for 'sam deploy'
    =========================================
    Stack Name [sam-app]: test-project
    AWS Region [us-east-1]: us-west-2
    #Shows you resources changes to be deployed and require a 'Y' to initiate deploy
    Confirm changes before deploy [y/N]: y
    #SAM needs permission to be able to create roles to connect to the resources in your template
    Allow SAM CLI IAM role creation [Y/n]: y
    Save arguments to samconfig.toml [Y/n]: y

After that, it will create a CloudFormation changeset for your Lambda function. Once you confirm to deploy the changeset, it will create the resources needed and deploy your Lambda function.

Previewing CloudFormation changeset before deployment
======================================================
Deploy this changeset? [y/N]: y

2020-04-01 13:42:20 - Waiting for stack create/update to complete

CloudFormation events from changeset
-------------------------------------------------------------------------------------------------------------------------------------------------------------
ResourceStatus                          ResourceType                            LogicalResourceId                       ResourceStatusReason
-------------------------------------------------------------------------------------------------------------------------------------------------------------
CREATE_IN_PROGRESS                      AWS::IAM::Role                          AppFunctionRole                         -
CREATE_IN_PROGRESS                      AWS::IAM::Role                          AppFunctionRole                         Resource creation Initiated
CREATE_COMPLETE                         AWS::IAM::Role                          AppFunctionRole                         -
CREATE_IN_PROGRESS                      AWS::Lambda::Function                   AppFunction                             -
CREATE_IN_PROGRESS                      AWS::Lambda::Function                   AppFunction                             Resource creation Initiated
CREATE_COMPLETE                         AWS::Lambda::Function                   AppFunction                             -
CREATE_COMPLETE                         AWS::CloudFormation::Stack              test-project                            -
-------------------------------------------------------------------------------------------------------------------------------------------------------------

Successfully created/updated stack - test-project in us-west-2

Once it’s done, you can verify that the resources are created by running the following command:

aws cloudformation describe-stack-resource --stack-name=test-project --logical-resource-id=AppFunction --query=StackResourceDetail.PhysicalResourceId

It will print out the name of the Lambda Function just created. To invoke the Lambda Function from the command line, copy the function name and run the following command:

aws lambda invoke —function-name=<FunctionName> response.json

The output will be something like this

{
"StatusCode": 200,
"ExecutedVersion": "$LATEST"
}

Clean Up

If you no longer need the resources, you can remove them by deleting the AWS CloudFormation stack using the following command:

aws cloudformation delete-stack —stack-name test-project

To verify the stack is delete, you need to run the following command and make sure the stack name you entered above is in the output

aws cloudformation list-stacks —stack-status-filter DELETE_COMPLETE

Conclusion

Archetypes codify best practices, and in this blog post we showed you how natural, and quick it is to get started with these Java Lambda templates using Maven. If you want to learn more about the Archetype, you can check out the archetype-lambda source code on Github. Please give this new archetype a try and let us know what you think via the GitHub issues page.