AWS Compute Blog
From Framework to Function: Deploying AWS Lambda Functions for Java 8 using Apache Maven Archetype
As a serverless computing platform that supports Java 8 runtime, AWS Lambda makes it easy to run any type of Java function simply by uploading a JAR file. To help define not only a Lambda serverless application but also Amazon API Gateway, Amazon DynamoDB, and other related services, the AWS Serverless Application Model (SAM) allows developers to use a simple AWS CloudFormation template.
AWS provides the AWS Toolkit for Eclipse that supports both Lambda and SAM. AWS also gives customers an easy way to create Lambda functions and SAM applications in Java using the AWS Command Line Interface (AWS CLI). After you build a JAR file, all you have to do is type the following commands:
aws cloudformation package aws cloudformation deploy
To consolidate these steps, customers can use Archetype by Apache Maven. Archetype uses a predefined package template that makes getting started to develop a function exceptionally simple.
In this post, I introduce a Maven archetype that allows you to create a skeleton of AWS SAM for a Java function. Using this archetype, you can generate a sample Java code example and an accompanying SAM template to deploy it on AWS Lambda by a single Maven action.
Prerequisites
Make sure that the following software is installed on your workstation:
- Java
- Maven
- AWS CLI
- (Optional) AWS SAM CLI
Install Archetype
After you’ve set up those packages, install Archetype with the following commands:
git clone https://github.com/awslabs/aws-serverless-java-archetype cd aws-serverless-java-archetype mvn install
These are one-time operations, so you don’t run them for every new package. If you’d like, you can add Archetype to your company’s Maven repository so that other developers can use it later.
With those packages installed, you’re ready to develop your new Lambda Function.
Start a project
Now that you have the archetype, customize it and run the code:
cd /path/to/project_home mvn archetype:generate \ -DarchetypeGroupId=com.amazonaws.serverless.archetypes \ -DarchetypeArtifactId=aws-serverless-java-archetype \ -DarchetypeVersion=1.0.0 \ -DarchetypeRepository=local \ # Forcing to use local maven repository -DinteractiveMode=false \ # For batch mode # You can also specify properties below interactively if you omit the line for batch mode -DgroupId=YOUR_GROUP_ID \ -DartifactId=YOUR_ARTIFACT_ID \ -Dversion=YOUR_VERSION \ -DclassName=YOUR_CLASSNAME
You should have a directory called YOUR_ARTIFACT_ID that contains the files and folders shown below:
├── event.json ├── pom.xml ├── src │ └── main │ ├── java │ │ └── Package │ │ └── Example.java │ └── resources │ └── log4j2.xml └── template.yaml
The sample code is a working example. If you install SAM CLI, you can invoke it just by the command below:
cd YOUR_ARTIFACT_ID mvn -P invoke verify [INFO] Scanning for projects... [INFO] [INFO] ---------------------------< com.riywo:foo >---------------------------- [INFO] Building foo 1.0 [INFO] --------------------------------[ jar ]--------------------------------- ... [INFO] --- maven-jar-plugin:3.0.2:jar (default-jar) @ foo --- [INFO] Building jar: /private/tmp/foo/target/foo-1.0.jar [INFO] [INFO] --- maven-shade-plugin:3.1.0:shade (shade) @ foo --- [INFO] Including com.amazonaws:aws-lambda-java-core:jar:1.2.0 in the shaded jar. [INFO] Replacing /private/tmp/foo/target/lambda.jar with /private/tmp/foo/target/foo-1.0-shaded.jar [INFO] [INFO] --- exec-maven-plugin:1.6.0:exec (sam-local-invoke) @ foo --- 2018/04/06 16:34:35 Successfully parsed template.yaml 2018/04/06 16:34:35 Connected to Docker 1.37 2018/04/06 16:34:35 Fetching lambci/lambda:java8 image for java8 runtime... java8: Pulling from lambci/lambda Digest: sha256:14df0a5914d000e15753d739612a506ddb8fa89eaa28dcceff5497d9df2cf7aa Status: Image is up to date for lambci/lambda:java8 2018/04/06 16:34:37 Invoking Package.Example::handleRequest (java8) 2018/04/06 16:34:37 Decompressing /tmp/foo/target/lambda.jar 2018/04/06 16:34:37 Mounting /private/var/folders/x5/ldp7c38545v9x5dg_zmkr5kxmpdprx/T/aws-sam-local-1523000077594231063 as /var/task:ro inside runtime container START RequestId: a6ae19fe-b1b0-41e2-80bc-68a40d094d74 Version: $LATEST Log output: Greeting is 'Hello Tim Wagner.' END RequestId: a6ae19fe-b1b0-41e2-80bc-68a40d094d74 REPORT RequestId: a6ae19fe-b1b0-41e2-80bc-68a40d094d74 Duration: 96.60 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 7 MB {"greetings":"Hello Tim Wagner."} [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 10.452 s [INFO] Finished at: 2018-04-06T16:34:40+09:00 [INFO] ------------------------------------------------------------------------
This maven goal invokes sam local invoke -e event.json
, so you can see the sample output to greet Tim Wagner.
To deploy this application to AWS, you need an Amazon S3 bucket to upload your package. You can use the following command to create a bucket if you want:
aws s3 mb s3://YOUR_BUCKET --region YOUR_REGION
Now, you can deploy your application by just one command!
mvn deploy \ -DawsRegion=YOUR_REGION \ -Ds3Bucket=YOUR_BUCKET \ -DstackName=YOUR_STACK [INFO] Scanning for projects... [INFO] [INFO] ---------------------------< com.riywo:foo >---------------------------- [INFO] Building foo 1.0 [INFO] --------------------------------[ jar ]--------------------------------- ... [INFO] --- exec-maven-plugin:1.6.0:exec (sam-package) @ foo --- Uploading to aws-serverless-java/com.riywo:foo:1.0/924732f1f8e4705c87e26ef77b080b47 11657 / 11657.0 (100.00%) Successfully packaged artifacts and wrote output template to file target/sam.yaml. Execute the following command to deploy the packaged template aws cloudformation deploy --template-file /private/tmp/foo/target/sam.yaml --stack-name <YOUR STACK NAME> [INFO] [INFO] --- maven-deploy-plugin:2.8.2:deploy (default-deploy) @ foo --- [INFO] Skipping artifact deployment [INFO] [INFO] --- exec-maven-plugin:1.6.0:exec (sam-deploy) @ foo --- Waiting for changeset to be created.. Waiting for stack create/update to complete Successfully created/updated stack - archetype [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 37.176 s [INFO] Finished at: 2018-04-06T16:41:02+09:00 [INFO] ------------------------------------------------------------------------
Maven automatically creates a shaded JAR file, uploads it to your S3 bucket, replaces template.yaml
, and creates and updates the CloudFormation stack.
To customize the process, modify the pom.xml
file. For example, to avoid typing values for awsRegion
, s3Bucket
or stackName
, write them inside pom.xml
and check in your VCS. Afterward, you and the rest of your team can deploy the function by typing just the following command:
mvn deploy
Options
Lambda Java 8 runtime has some types of handlers: POJO, Simple type and Stream. The default option of this archetype is POJO style, which requires to create request and response classes, but they are baked by the archetype by default. If you want to use other type of handlers, you can use handlerType
property like below:
## POJO type (default) mvn archetype:generate \ ... -DhandlerType=pojo ## Simple type - String mvn archetype:generate \ ... -DhandlerType=simple ### Stream type mvn archetype:generate \ ... -DhandlerType=stream
See documentation for more details about handlers.
Also, Lambda Java 8 runtime supports two types of Logging class: Log4j 2 and LambdaLogger. This archetype creates LambdaLogger implementation by default, but you can use Log4j 2 if you want:
## LambdaLogger (default) mvn archetype:generate \ ... -Dlogger=lambda ## Log4j 2 mvn archetype:generate \ ... -Dlogger=log4j2
If you use LambdaLogger, you can delete ./src/main/resources/log4j2.xml
. See documentation for more details.
Conclusion
So, what’s next? Develop your Lambda function locally and type the following command: mvn deploy
!
With this Archetype code example, available on GitHub repo, you should be able to deploy Lambda functions for Java 8 in a snap. If you have any questions or comments, please submit them below or leave them on GitHub.