Переходите на бессерверные технологии с помощью Java, Spring и AWS SAM

После предыдущего поста о создании бессерверного REST API с помощью TypeScript и NestJS мы собираемся погрузиться в некоторые другие технологии. В этой истории мы создадим бессерверный REST API с помощью AWS SAM, Java и Spring. В качестве инструмента сборки мы выбираем Gradle, самый быстрый инструмент для автоматизации процесса сборки, широко поддерживаемый IDE в пространстве Java.

Не знаете, что может предложить бессерверная технология? Прочитайте мою предыдущую статью, как бессерверные технологии помогают вам строить быстрее.

API будет работать на AWS Lambda и связан со шлюзом API (см. диаграмму ниже). Эта бессерверная архитектура позволяет запускать службу с моделью ценообразования с оплатой за запрос с минимальным эксплуатационным обслуживанием.

Давайте быстро представим задействованные технологии, чтобы вы лучше поняли, что мы будем строить здесь.

АМС СЭМ

Модель бессерверных приложений AWS¹ (AWS SAM) — это собственная технология AWS, помогающая создавать, тестировать и развертывать функции AWS Lambda. Там, где я ранее использовал инфраструктуру Serverless для подключения, AWS SAM лучше подходит для функций Lambda, выполняемых с помощью Java.

Для локального запуска и тестирования Lambda с помощью AWS SAM вам также необходимо установить Docker.

Весенняя структура

Фреймворк Spring — самый популярный фреймворк с открытым исходным кодом для Java. Он предлагает множество модулей для Интернета, базы данных, интеграции и многого другого. Spring позволяет разработчикам использовать POJO и скрывает сложность. Разработчики более продуктивны, используя среду Spring. Центральным элементом среды Spring является шаблон Inversion of Control². Контейнер Spring IoC обрабатывает создание объектов и внедрение зависимостей, обеспечивая более слабую связь между классами, что обеспечивает гибкость.

Грейдл

Gradle — это самый быстрый инструмент сборки для Java, повышающий вашу производительность по сравнению с Maven.

Выбор дизайна

Существует множество способов создать REST API с помощью AWS Lambda. В этой истории я сделал следующие выборы:

Интеграция API-шлюза с прокси-сервером Lambda. Если вы обычно сопоставляете каждый запрос API в шлюзе API с функцией Lambda, интеграция с прокси-сервером³ позволяет сопоставлять все запросы API с одной функцией Lambda. Такое отделение от шлюза API избавляет вас от необходимости управлять конфигурацией API в шлюзе API и ускоряет процесс разработки. Объединение функций одного домена в один сервис вполне подходит для микросервисной архитектуры.

Дополнительным эффектом является то, что функции комплектации уменьшают вероятность холодного запуска.

Это требует, чтобы вы сами обрабатывали входящие запросы. Как мы увидим, среда Spring более чем способна сделать это без особых усилий.

Бессерверный Java-контейнер

Существует несколько платформ, которые следует рассмотреть для реализации AWS Lambda с Java, например, Spring Cloud. Однако я решил использовать фреймворк Serverless Java Container от AWS Labs. Он поддерживается AWS и предоставляет очень тонкую Java-оболочку, работающую под управлением Spring внутри Lambda. Обоснование: меньше кода, меньше холодный старт.

Начнем строить

Итак, теперь мы знаем, какие технологии будем использовать и в каком направлении движемся, приступим к строительству. Мы создадим сервис онлайн-библиотеки как REST API, работающий на AWS Lambda с Java и Spring.

Полный проект для этой статьи можно найти на Github https://github.com/cyberworkz/examples в папке online-library-java.

Предпосылки

  1. Аккаунт AWS — смотрите эту историю для помощи по его настройке.
  2. Базовые знания Java и Spring

Установить AWS SAM

Интерфейс командной строки AWS SAM упрощает создание бессерверных приложений и управление ими. Установите его на свою ОС по следующей ссылке.

Проект установки

Теперь SAM установлен, мы будем использовать его для настройки нашего бессерверного проекта. Мы будем использовать предопределенный шаблон, чтобы взяться за дело. Выполните следующую команду для создания проекта:

sam init --location gh:cyberworkz/sam-templates

Это создаст проект Java Spring с использованием шаблона прокси со всеми необходимыми зависимостями. Сгенерированный проект имеет файл шаблона AWS SAM, который точно соответствует формату AWS CloudFormation. Файл template.yml должен выглядеть следующим образом:

Давайте обсудим наиболее важные параметры в этом файле. С помощью файла шаблона вы можете определить следующие параметры для вашего Lambda:

  • среда выполнения (java11)
  • объем памяти (512)
  • CodeUri и класс обработчика.

Также обратите внимание на раздел событий, в котором мы определяем стиль интеграции прокси с шлюзом API.

Events:        
  Service:          
    Type: Api 
    Properties:            
      Path: /{proxy+}            
      Method: any

Параметр CodeUri определяет пакет Java, который развертывается как лямбда-код. Файл сборки Gradle содержит задачу shadowJar, которая будет собирать код, включая все классы из зависимостей, чтобы его можно было запустить.

Обработчик запросов

Теперь мы создали проект. Мы рассмотрим код, который будет обрабатывать входящий запрос от шлюза API. Класс StreamLambdaHandler обрабатывает входящие запросы.

Класс содержит статический раздел, который вызывается на этапе инициализации. Используйте это для настройки соединений с ресурсами в качестве базы данных. После обработки запроса эти ресурсы сохраняются при следующем вызове.

Метод handleRequest обрабатывает запрос как Inputstream и возвращает OutputStream в качестве ответа. Метод проксирует вызов SpringLambdaContainer, позволяя нам применить магию фреймворка Spring.

Контекстные методы

Объект контекста содержит хуки для получения информации о запросе. В следующем списке показано, что может доставить объект контекста.

  • getRemainingTimeInMillis() — возвращает количество миллисекунд, оставшихся до истечения времени выполнения.
  • getFunctionName() — возвращает имя лямбда-функции.
  • getFunctionVersion() — Возвращает версию функции.
  • getInvokedFunctionArn() — возвращает имя ресурса Amazon (ARN), которое используется для вызова функции. Указывает, указал ли инициатор номер версии или псевдоним.
  • getMemoryLimitInMB() — возвращает объем памяти, выделенный для функции.
  • getAwsRequestId() — возвращает идентификатор запроса на вызов.
  • getLogGroupName() — возвращает группу журнала для функции.
  • getLogStreamName() — возвращает поток журнала для экземпляра функции.
  • getIdentity() — (мобильные приложения) возвращает информацию об удостоверении Amazon Cognito, которое авторизовало запрос.
  • getClientContext() — (мобильные приложения) возвращает клиентский контекст, предоставленный Lambda клиентским приложением.
  • getLogger() — Возвращает объект логгера для функции.

Конечные точки API

Теперь перейдем к определению конечных точек API. Мы используем шаблон интеграции с прокси, при котором каждый запрос к шлюзу API перенаправляется в лямбда-код. Используя Spring MVC, мы можем очень легко определить конечные точки с помощью аннотаций. См. код для OnlineLibraryController.java ниже:

Аннотация EnableWebMvc сигнализирует о том, что вы будете использовать аннотации для настройки сопоставления запросов. Аннотация RestController сигнализирует о том, что класс является управляемым компонентом в среде Spring и будет инициирован при запуске контейнера Spring.

В аннотации RequestMapping указывается путь, на который будут сопоставлены методы класса контроллера. Аннотация GetMapping является специализацией RequestMapping и сопоставляет методы с запросами GET. Значение аннотации GetMapping добавляется к RequestMapping, определенному на уровне класса, и может содержать переменные пути. URL-адрес /books/author/tolkien/jrr в этом примере сопоставляется с методом getBooksByAuthor.

Некоторые другие важные аннотации, используемые для сопоставления входящих HTTP-запросов:

  • PostMapping
  • PutMapping
  • PathVariable
  • RequestParam
  • Headers
  • RequestBody
  • ResponseBody

Я надеюсь, что это демонстрирует, как легко запросы сопоставляются с различными методами с помощью аннотаций SpringMVC, и избавляет вас от усилий по управлению сопоставлениями в шлюзе API.

Итак, на этом все заканчивается. Я надеюсь, что это поможет вам в ваших бессерверных путешествиях. Опять же, код этого проекта можно найти на GitHub. https://github.com/cyberworkz/examples в папке online-library-java.

Спасибо за прочтение!

Хайко ван дер Шааф

  • Если вам понравилось, подпишитесь на Serverlesscorner.com на Medium.
  • Любите❤️ читать мои и другие истории на Medium? Стань участником, если вы еще этого не сделали.
  • Хотите узнать больше о бессерверных технологиях? Подпишитесь на мою ежемесячную рассылку 📬 о вдохновляющих и познавательных историях о бессерверных технологиях и примерах их использования.

Рекомендации

  1. https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/what-is-sam.html
  2. https://en.wikipedia.org/wiki/Inversion_of_control
  3. https://docs.aws.amazon.com/apigateway/latest/developerguide/set-up-lambda-proxy-integrations.html