1. Что такое Micronaut
Micronaut — это фреймворк на JVM для построения легковесных модульных приложений. Он разработан компанией OCI, той же компанией, что подарила нам Grails. Micronaut это современный фреймворк, призванный сделать создание микросервисных приложений быстрым и простым.
Micronaut содержит возможности похожие на существующие фреймворки, такие как Spring, но в то же время он реализует некоторые новые идеи, которые являются его отличительными чертами. Вместе с поддержкой Java, Groovy и Kotlin он предлагает множество путей создания приложений.
2. Основные возможности
Одна из самых захватывающих возможностей Micronaut это внедрение зависимостей (DI) во время компиляции. Большинство фреймворков используют рефлексию и прокси-объекты для внедрения зависимостей во время исполнения. Micronaut же собирает данные для внедрения зависимостей на этапе компиляции. Результат этого — быстрое время старта приложений и меньшее потребление памяти.
Следующая его возможность это первоклассная поддержка реактивного программирования, как для клиентов, так и для серверов. Выбор специфичной реализации реактивного подхода оставлен за разработчиками решений, а RxJava и Project Reactor поддерживаются из коробки.
Плюс, у Micronaut есть несколько возможностей, которые делают его отличным фреймворком для разработки облачных приложений (cloud-native). Он поддерживает множество механизмов обнаружения сервисов (service discovery), такие как Eureka и Consul, а также работает с различными системами распределённой трассировки (distributed tracing), такими как Zipkin и Jaeger.
Дополнительно, он предоставляет поддержку создания лямбда функций AWS, позволяя легко создавать бессерверные приложения (serverless).
3. Начало работы
Самый простой способ начать — использовать SDKMAN:
> sdk install micronaut 1.0.0.M2
SDKMAN установит все бинарные файлы, которые понадобятся вам для сборки, тестирования и развёртывания Micronaut приложений. Кроме того, вы получите консольное приложение Micronaut CLI, позволяющее с лёгкостью начать новый проект.
Бинарные артефакты также доступны в Sonatype и на Github.
В следующих разделах мы посмотрим на некоторые возможности Micronaut.
4. Внедрение зависимостей (DI)
Как упоминалось ранее, Micronaut обрабатывает внедрение зависимостей на этапе компиляции, что отличает его от большинства IoC контейнеров.
Однако, он полностью поддерживает аннотации JSR-330, так что работа с бинами похожа на другие IoC фреймворки.
Чтобы инжектировать бин в нашем коде мы используем
@Inject
:@Inject
private EmployeeService service;
Аннотация
@Inject
работает также как @Autowired
и может использоваться с полями, методами, конструкторами и параметрами.По умолчанию, все бины имееют область видимости (scope) — prototype. Мы можем быстро создать синглтоны, используя аннотацию
@Singleton
. Если множество бинов реализуют один и тот же интерфейс, мы можем использовать аннотацию @Primary
чтобы разрешить конфликт:@Primary
@Singleton
public class BlueCar implements Car {}
Аннотация
@Requires
может использоваться, когда бины опциональны, или чтобы выполнить инъекцию при выполнении определённых условий.В этом плане, он ведёт себя так же, как аннотация 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. Внутри этого каталога мы найдём основной код приложения, POM файл Maven и другие файлы проекта.
Простейшее приложение выглядит так:
public class ServerApplication {
public static void main(String[] args) {
Micronaut.run(ServerApplication.class);
}
}
5.1 Блокирующий HttpRequest
Само по себе приложение не делает почти ничего. Давайте добавим контроллер с двумя обработчиками. Оба будут возвращать приветствие, но один будет отвечать на 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;
}
}
От переводчика: ваш покорный слуга пошёл и проделал всё, что рассказывается в этой статье. Если вы на этом этапе собрались запустить приложение и посмотреть, работает ли оно, то не забудьте включить Annotation Processing в Eclipse / IntelliJ IDEA.
5.2 Реактивный IO
По умолчанию, Micronaut реализует эти обработчики в виде традиционного блокирующего I/O. Однако, мы можем быстро реализовать неблокирующие обработчики, всего то изменив возвращаемый тип на любой из реактивных неблокирующих типов.
Например, с RxJava мы можем использовать
Observable
. Похожим образом, с Reactor мы можем вернуть типы Mono
или Flux
:@Get("/{name}")
public Mono<String> greet(String name) {
return Mono.just(greetingService.getGreeting() + name);
}
От переводчика: для этого примера вам понадобится Project Reactor в зависимостях Maven:
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.1.8.RELEASE</version>
</dependency>
Как для блокирующих, так и для неблокирующих обработчиков используется HTTP сервер Netty.
Обычно, запросы обрабатываются в основном I/O пуле потоков, который создаётся при запуске, что делает их блокирующимися.
Однако, если обработчик возвращает неблокирующие типы данных, то Micronaut использует цикл обработки событий Netty, делая весь запрос неблокирующим.
6. Создаём HTTP клиент
Теперь, давайте создадим клиентское приложение для обработчиков, которые только что создали. Micronaut предоставляет два способа создания 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 клиента
Есть вариант создания традиционного 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");
}
}
Клиент по умолчанию использует RxJava, так что вы легко можете использовать блокирующие и неблокирующие вызовы.
7. Micronaut CLI
Мы уже видели, как работает утилита Micronaut CLI, когда создавали приложение.
В нашем случае это было отдельное приложение, но эта утилита поддерживает несколько других возможностей.
7.1 Проекты из множества приложений (Federation)
В 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
От переводчика: ну а тут не удивляйтесь, команду надо запускать вне каталога проекта. В каталоге проекта не работает, может в .M3 версии починили. Она уже вышла.
7.3 Существующие Проекты
Мы можем использовать CLI для модификации существующих проектов. Это позволяет нам создавать бины, клиенты, контроллеры, и т.д. Когда мы запускаем команду «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 сервера и клиенты. Также мы взглянули на пару возможностей CLI.
Это всего лишь небольшой кусочек пирога, который предлагает Micronaut. Под капотом у него поддержка функций serverless, обнаружения сервисов, распределённой трассировки, мониторинга и метрик, распределённых конфигураций и много чего ещё.
Вместе с тем, что многие возможности Micronaut были заимствованы из существующих фреймворков, таких как Grails и Spring, он предлагает уникальные возможности, которые его выделяют на фоне других.
Комментарии (13)
Moxa
25.07.2018 14:02А как у него с производительностью? Когда я пару месяцев назад пытался бенчмаркать, не работали keep-alive реквесты =(
EreminD
Хм. Пока выглядит один в один как спринг бут
Но не ясно, чем это лучше? Может быть, есть какая-то киллер-фича?
Со всем уважением
jreznot Автор
Как заявляют авторы — молниеносный запуск, что важно для микросервисов и serverless, когда нужно быстро масштабироваться.
fzn7
Похоже что киллерфичей является di на этапе компиляции. Вместе с aot компиляцией в бинарник получается замена c++ демонам
jreznot Автор
Они как раз вовремя с этим всем, jlink и Java 11 позволят всё нормально так утромбовать.
kefirfromperm
Расходование памяти в разы меньше.
fRoStBiT
Судя по всему, оно позиционируется как подобие Spring Boot с Dagger вместо Spring Core.
mad_nazgul
В самом начале написано, что контекст создается на этапе компиляции, а не исполнения.
Из-за этого не тратиться время на поднятие контекста. :-)