-
Notifications
You must be signed in to change notification settings - Fork 560
Quick start Spring
You can use the aws-serverless-java-container
library to run a Spring application in AWS Lambda. You can use the library within your Lambda handler to load your Spring application and proxy events to it.
In the repository we have included a sample Spring application to get you started.
You can quickly create a new serverless Spring application using our Maven archetype. First, make sure Maven is installed in your environment and available in your PATH
. Next, using a terminal or your favorite IDE create a new application, the archetype groupId
is com.amazonaws.serverless.archetypes
and the artifactId
is aws-serverless-spring-archetype
;
mvn archetype:generate -DgroupId=my.service -DartifactId=my-service -Dversion=1.0-SNAPSHOT \
-DarchetypeGroupId=com.amazonaws.serverless.archetypes \
-DarchetypeArtifactId=aws-serverless-spring-archetype \
-DarchetypeVersion=1.1.2
The archetype sets up a new maven project. The pom.xml
includes the dependencies you will need to build a basic Spring API. The generated code includes a StreamLambdaHandler
class, the main entry point for AWS Lambda; a SpringApiConfig
class that defines a basic Spring application; a controller
package with a /ping
resource; and a set of unit tests that exercise the application.
The project also includes a file called sam.yaml
. This is a SAM template that you can use to quickly test your application in local or deploy it to AWS. Open the README.md
file in the project root folder for instructions on how to use SAM Local to run your Serverless API or deploy it to AWS.
The first step is to import the Spring implementation of the library:
<dependency>
<groupId>com.amazonaws.serverless</groupId>
<artifactId>aws-serverless-java-container-spring</artifactId>
<version>1.1</version>
</dependency>
This will automatically also import the aws-serverless-java-container-core
and aws-lambda-java-core
libraries.
Dependency injection with Spring can have a significant impact on your function's cold start time. To address this, you can include the spring-context-indexer
dependency to generate a list of candidate components at compile time.
In your application package declare a new class that implements Lambda's RequestStreamHandler
interface. If you have configured API Gateway with a proxy integration, you can use the built-in POJOs AwsProxyRequest
and AwsProxyResponse
.
The next step is to declare the container handler object. The library exposes a utility static method that configures a SpringLambdaContainerHandler
object for AWS proxy events. The method receives a class annotated with Spring's @Configuration
that defines your application. The object should be declared as a class property and be static. By doing this, Lambda will re-use the instance for subsequent requests.
The handleRequest
method of the class can use the handler
object we declared in the previous step to send requests to the Spring application.
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
handler = SpringLambdaContainerHandler.getAwsProxyHandler(PetStoreSpringAppConfig.class);
} catch (ContainerInitializationException e) {
// if we fail here. We re-throw the exception to force another cold start
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring framework", e);
}
}
@Override
public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context)
throws IOException {
handler.proxyStream(inputStream, outputStream, context);
// just in case it wasn't closed by the mapper
outputStream.close();
}
}
In our sample application The PetStoreSpringAppConfig
class contains the configuration.
@Configuration
@ComponentScan("com.amazonaws.serverless.sample.spring")
public class PetStoreSpringAppConfig {
}
You can follow the instructions in AWS Lambda's documentation on how to package your function for deployment.
There are two ways to activate Spring Profiles (as defined with the @Profile
annotation). We recommend using the static initializer that receives a list of profiles. The Serverless Java Container framework takes care of setting the profile and initializing the application at once.
public class StreamLambdaHandler implements RequestStreamHandler {
private static SpringLambdaContainerHandler<AwsProxyRequest, AwsProxyResponse> handler;
static {
try {
AnnotationConfigWebApplicationContext applicationContext = new AnnotationConfigWebApplicationContext();
applicationContext.register(PetStoreSpringAppConfig.class);
handler = SpringLambdaContainerHandler.getAwsProxyHandler(applicationContext, "profile-1", "profile-2");
} catch (ContainerInitializationException e) {
// if we fail here. We re-throw the exception to force another cold start
e.printStackTrace();
throw new RuntimeException("Could not initialize Spring framework", e);
}
}
...
}
If you need to reload profiles at runtime, you can use the SpringLambdaContainerHandler.activateSpringProfiles(String...)
method - be aware that this operation causes the entire application context to reload, making the following request slower. See @Profile
documentation for details.