Serverless функции на Java с AWS Lambda: от идеи до деплоя
Serverless-архитектура (или бессерверные вычисления) — это модель облачных вычислений, где разработчик полностью абстрагируется от управления серверами. Вы просто пишете код, загружаете его в облако, а провайдер (AWS, Google Cloud, Azure) автоматически масштабирует инфраструктуру. AWS Lambda — флагманский сервис Amazon в этой области. В этой статье мы разберем, как создавать serverless функции на Java, используя AWS Lambda, с нуля до production-готового примера.
Что такое AWS Lambda и почему Java?
AWS Lambda позволяет выполнять код в ответ на события (HTTP-запросы, загрузки файлов в S3, изменения в DynamoDB и т.д.) без выделения виртуальных машин. Вы платите только за фактическое время выполнения и количество запросов.
Java — зрелый, статически типизированный язык с огромной экосистемой библиотек (Spring, Micronaut, Quarkus). Однако у Java есть особенности для serverless: холодный старт (время загрузки JVM) может быть выше, чем у Node.js или Python. Но современные фреймворки (например, Quarkus или Spring Cloud Function) и использование GraalVM Native Image решают эту проблему, делая Java конкурентоспособным выбором.
Настройка окружения для разработки
Для работы с AWS Lambda на Java вам понадобится:
- JDK 11 или 17 (рекомендуется 17 для лучшей производительности).
- Maven или Gradle (мы используем Maven).
- Учетная запись AWS и установленный AWS CLI.
- IDE (IntelliJ IDEA, Eclipse, VS Code).
Создайте базовый Maven-проект. Добавьте в pom.xml зависимость для AWS Lambda Java Core:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-core</artifactId>
<version>1.2.3</version>
</dependency>
Также добавьте плагин для сборки:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.0</version>
<executions>
<execution>
<phase>package</phase>
<goals><goal>shade</goal></goals>
</execution>
</executions>
</plugin>
Создание первой Lambda-функции на Java
Создайте класс HelloLambda.java:
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.RequestHandler;
public class HelloLambda implements RequestHandler<String, String> {
@Override
public String handleRequest(String input, Context context) {
context.getLogger().log("Input: " + input);
return "Hello, " + input + "! Ваша Lambda-функция на Java выполнена.";
}
}
Пояснение:
RequestHandler<String, String>— интерфейс, где первый тип — входные данные, второй — возвращаемый тип.Context— объект, предоставляющий информацию о среде выполнения (логгер, время, имя функции).
Соберите проект: mvn clean package. В папке target появится JAR-файл (например, lambda-java-1.0-SNAPSHOT.jar).
Деплой функции в AWS Lambda
Деплой можно выполнить через AWS Console или CLI. Рассмотрим CLI (самый быстрый способ):
aws lambda create-function \
--function-name HelloJavaLambda \
--runtime java17 \
--role arn:aws:iam::YOUR_ACCOUNT_ID:role/lambda-basic-execution \
--handler HelloLambda::handleRequest \
--zip-file fileb://target/lambda-java-1.0-SNAPSHOT.jar
Важные параметры:
--runtime java17— указывает Java 17 (также доступны java11, java8).--role— IAM-роль с правами на запись логов в CloudWatch.--handler— полное имя класса и метода (формат:ClassName::methodName).
После успешного создания, протестируйте функцию:
aws lambda invoke \
--function-name HelloJavaLambda \
--payload '"Мир"' \
response.json
cat response.json
Вывод: "Hello, Мир! Ваша Lambda-функция на Java выполнена."
Продвинутые сценарии: работа с событиями и базами данных
Рассмотрим пример Lambda-функции, которая обрабатывает загрузку файла в S3 и записывает метаданные в DynamoDB. Добавьте зависимости в pom.xml:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-lambda-java-events</artifactId>
<version>3.11.4</version>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>dynamodb</artifactId>
<version>2.21.0</version>
</dependency>
Код функции:
import com.amazonaws.services.lambda.runtime.Context;
import com.amazonaws.services.lambda.runtime.events.S3Event;
import software.amazon.awssdk.services.dynamodb.DynamoDbClient;
import software.amazon.awssdk.services.dynamodb.model.PutItemRequest;
import software.amazon.awssdk.services.dynamodb.model.AttributeValue;
import java.util.Map;
public class S3ToDynamoDBHandler implements RequestHandler<S3Event, String> {
private final DynamoDbClient dynamoDb = DynamoDbClient.create();
private static final String TABLE_NAME = "FileMetadata";
@Override
public String handleRequest(S3Event event, Context context) {
event.getRecords().forEach(record -> {
String bucketName = record.getS3().getBucket().getName();
String objectKey = record.getS3().getObject().getKey();
long size = record.getS3().getObject().getSizeAsLong();
Map<String, AttributeValue> item = Map.of(
"bucketName", AttributeValue.builder().s(bucketName).build(),
"objectKey", AttributeValue.builder().s(objectKey