Перейти к основному содержимому

Введение в Micronaut Framework

· 7 мин. чтения

1. Что такое Микронавт

Micronaut — это платформа на основе JVM для создания легких модульных приложений. Micronaut, разработанный OCI, той же компанией, которая создала Grails, представляет собой новейшую платформу, предназначенную для быстрого и простого создания микросервисов .

Хотя Micronaut содержит некоторые функции, похожие на существующие фреймворки, такие как Spring, он также имеет некоторые новые функции, которые отличают его от других. А благодаря поддержке Java, Groovy и Kotlin он предлагает множество способов создания приложений.

2. Основные характеристики

Одной из самых интересных особенностей Micronaut является механизм внедрения зависимостей во время компиляции. Большинство фреймворков используют отражение и прокси-серверы для внедрения зависимостей во время выполнения. Однако Micronaut создает данные для внедрения зависимостей во время компиляции. Результатом является более быстрый запуск приложений и меньший объем памяти.

Еще одна особенность — первоклассная поддержка реактивного программирования как для клиентов, так и для серверов. Выбор конкретной реактивной реализации остается за разработчиком, поскольку поддерживаются как RxJava, так и Project Reactor.

Micronaut также имеет несколько функций, которые делают его отличной средой для разработки облачных приложений. Он поддерживает несколько инструментов обнаружения сервисов, таких как Eureka и Consul, а также работает с различными системами распределенной трассировки, такими как Zipkin и Jaeger.

Он также поддерживает создание лямбда-функций AWS, упрощая создание бессерверных приложений.

3. Начало работы

Самый простой способ начать работу — использовать SDKMAN :

> sdk install micronaut 1.0.0.RC2

Это установит все двоичные файлы, которые нам понадобятся для сборки, тестирования и развертывания приложений Micronaut. Он также предоставляет инструмент командной строки Micronaut, который позволяет нам легко начинать новые проекты.

Двоичные артефакты также доступны на Sonatype и GitHub .

В следующих разделах мы рассмотрим некоторые особенности фреймворка.

4. Внедрение зависимостей

Как упоминалось ранее, Micronaut обрабатывает внедрение зависимостей во время компиляции, что отличается от большинства контейнеров IoC.

Однако он по-прежнему полностью поддерживает аннотации JSR-330 , поэтому работа с bean-компонентами аналогична другим платформам IoC.

Чтобы автоматически связать bean-компонент с нашим кодом, мы используем @Inject:

@Inject
private EmployeeService service;

Аннотация @Inject работает так же, как и @Autowired, и может использоваться в полях, методах, конструкторах и параметрах.

По умолчанию все bean-компоненты имеют область видимости прототипа. Мы можем быстро создавать одноэлементные компоненты с помощью @Singleton. Если несколько классов реализуют один и тот же интерфейс bean-компонента, @Primary можно использовать для их устранения конфликтов:

@Primary
@Singleton
public class BlueCar implements Car {}

Аннотацию @Requires можно использовать, когда bean-компоненты являются необязательными, или для выполнения автоматического связывания только при выполнении определенных условий.

В этом отношении он ведет себя так же, как аннотации Spring Boot @Conditional :

@Singleton
@Requires(beans = DataSource.class)
@Requires(property = "enabled")
@Requires(missingBeans = EmployeeService)
@Requires(sdk = Sdk.JAVA, value = "1.8")
public class JdbcEmployeeService implements EmployeeService {}

5. Создание HTTP-сервера

Теперь давайте рассмотрим создание простого приложения HTTP-сервера. Для начала мы будем использовать SDKMAN для создания проекта:

> mn create-app hello-world-server -build maven

Это создаст новый проект Java с использованием Maven в каталоге с именем hello-world-server. Внутри этого каталога мы найдем наш основной исходный код приложения, файл Maven POM и другие вспомогательные файлы для проекта.

Приложение по умолчанию, очень простое:

public class ServerApplication {
public static void main(String[] args) {
Micronaut.run(ServerApplication.class);
}
}

5.1. Блокировка HTTP

Само по себе это приложение мало что даст. Давайте добавим контроллер с двумя конечными точками. Оба вернут приветствие, но один будет использовать HTTP-глагол GET , а другой — POST:

@Controller("/greet")
public class GreetController {

@Inject
private GreetingService greetingService;

@Get("/{name}")
public String greet(String name) {
return greetingService.getGreeting() + name;
}

@Post(value = "/{name}", consumes = MediaType.TEXT_PLAIN)
public String setGreeting(@Body String name) {
return greetingService.getGreeting() + name;
}
}

5.2. Реактивный ввод-вывод

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

Например, с RxJava мы можем использовать Observable . Точно так же при использовании Reactor мы можем возвращать типы данных Mono или Flux :

@Get("/{name}")
public Mono<String> greet(String name) {
return Mono.just(greetingService.getGreeting() + name);
}

Как для блокирующих, так и для неблокирующих конечных точек Netty является базовым сервером, используемым для обработки HTTP-запросов.

Обычно запросы обрабатываются в основном пуле потоков ввода-вывода, который создается при запуске, что приводит к их блокировке.

Однако, когда из конечной точки контроллера возвращается неблокирующий тип данных, Micronaut использует поток цикла событий Netty, делая весь запрос неблокирующим.

6. Создание HTTP-клиента

Теперь давайте создадим клиент для использования только что созданных конечных точек. Micronaut предоставляет два способа создания HTTP-клиентов:

  • Декларативный HTTP-клиент
  • Программный HTTP-клиент

6.1. Декларативный HTTP-клиент

Первый и самый быстрый способ создания — использование декларативного подхода:

@Client("/greet")
public interface GreetingClient {
@Get("/{name}")
String greet(String name);
}

Обратите внимание, что мы не реализуем никакого кода для вызова нашего сервиса . Вместо этого Micronaut понимает, как вызывать сервис, исходя из сигнатуры метода и предоставленных нами аннотаций.

Чтобы протестировать этот клиент, мы можем создать тест JUnit, который использует API встроенного сервера для запуска встроенного экземпляра нашего сервера:

public class GreetingClientTest {
private EmbeddedServer server;
private GreetingClient client;

@Before
public void setup() {
server = ApplicationContext.run(EmbeddedServer.class);
client = server.getApplicationContext().getBean(GreetingClient.class);
}

@After
public void cleanup() {
server.stop();
}

@Test
public void testGreeting() {
assertEquals(client.greet("Mike"), "Hello Mike");
}
}

6.2. Программный HTTP-клиент

У нас также есть возможность написать более традиционный клиент, если нам нужно больше контроля над его поведением и реализацией:

@Singleton
public class ConcreteGreetingClient {
private RxHttpClient httpClient;

public ConcreteGreetingClient(@Client("/") RxHttpClient httpClient) {
this.httpClient = httpClient;
}

public String greet(String name) {
HttpRequest<String> req = HttpRequest.GET("/greet/" + name);
return httpClient.retrieve(req).blockingFirst();
}

public Single<String> greetAsync(String name) {
HttpRequest<String> req = HttpRequest.GET("/async/greet/" + name);
return httpClient.retrieve(req).first("An error as occurred");
}
}

HTTP-клиент по умолчанию использует RxJava, поэтому может легко работать с блокирующими или неблокирующими вызовами.

7. Интерфейс командной строки Микронавта

Мы уже видели инструмент Micronaut CLI в действии выше, когда использовали его для создания нашего примера проекта.

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

7.1. Проекты Федерации

В Micronaut федерация — это просто группа автономных приложений, находящихся в одном каталоге. Используя федерации, мы можем легко управлять ими вместе и гарантировать, что они получают одинаковые значения по умолчанию и настройки.

Когда мы используем инструмент CLI для создания федерации, он принимает все те же аргументы, что и команда create-app . Он создаст структуру проекта верхнего уровня, и каждое отдельное приложение будет создано в своем подкаталоге оттуда.

7.2. Функции

При создании отдельного приложения или федерации мы можем решить, какие функции нужны нашему приложению . Это помогает обеспечить включение в проект минимального набора зависимостей.

Мы указываем функции, используя аргумент -features и предоставляя список имен функций, разделенных запятыми.

Мы можем найти список доступных функций, выполнив следующую команду:

> mn profile-info service

Provided Features:
--------------------
* annotation-api - Adds Java annotation API
* config-consul - Adds support for Distributed Configuration with Consul
* discovery-consul - Adds support for Service Discovery with Consul
* discovery-eureka - Adds support for Service Discovery with Eureka
* groovy - Creates a Groovy application
[...] More features available

7.3. Существующие проекты

Мы также можем использовать инструмент CLI для изменения существующих проектов. Это позволяет нам создавать bean-компоненты, клиенты, контроллеры и многое другое. Когда мы запускаем команду mn из существующего проекта, у нас будет новый набор доступных команд:

> mn help
| Command Name Command Description
-----------------------------------------------
create-bean Creates a singleton bean
create-client Creates a client interface
create-controller Creates a controller and associated test
create-job Creates a job with scheduled method

8. Заключение

В этом кратком введении в Micronaut мы увидели, как легко создавать как блокирующие, так и неблокирующие HTTP-серверы и клиенты. Кроме того, мы изучили некоторые особенности его интерфейса командной строки.

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

И хотя многие его функции получены из существующих фреймворков, таких как Grails и Spring, он также имеет множество уникальных функций, которые выделяют его самостоятельно.

Как всегда, мы можем найти примеры кода выше в нашем репозитории GitHub .