Вступ до Micronaut Framework

1. Що таке мікронавт

Micronaut - це платформа на основі JVM для створення легких, модульних додатків. Розроблений OCI, тією ж компанією, яка створила Grails, Micronaut - це найновіший фреймворк, розроблений для швидкого та легкого створення мікропослуг .

Хоча 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 CLI, який дозволяє нам легко починати нові проекти.

Бінарні артефакти також доступні на Sonatype та GitHub.

У наступних розділах ми розглянемо деякі особливості фреймворку.

4. Ін’єкція залежності

Як вже згадувалося раніше, Micronaut обробляє ін'єкцію залежностей під час компіляції, яка відрізняється від більшості контейнерів IoC.

Однак він все ще повністю підтримує анотації JSR-330, тому робота з компонентами схожа на інші фреймворки IoC.

Для автоматичного підключення компонента до нашого коду ми використовуємо @Inject:

@Inject private EmployeeService service;

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

За замовчуванням усі боби розглядаються як прототип. Ми можемо швидко створити одиночні боби за допомогою @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. Усередині цього каталогу ми знайдемо основний вихідний код програми, файл Maven POM та інші файли підтримки проекту.

Програма за замовчуванням дуже проста:

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

5.1. Блокування HTTP

Сам по собі цей додаток не зробить багато. Додамо контролер, який має дві кінцеві точки. Обидва повернуть привітання, але один використовуватиме дієслово GET HTTP, а інший - 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. Реактивний IO

За замовчуванням Micronaut реалізує ці кінцеві точки, використовуючи традиційні блокуючі введення-виведення. Однак ми можемо швидко реалізувати неблокуючі кінцеві точки, просто змінивши тип повернення на будь-який реактивний неблокуючий тип .

Наприклад, з RxJava ми можемо використовувати Observable . Аналогічним чином, використовуючи Reactor, ми можемо повернути типи даних Mono або Flux :

@Get("/{name}") public Mono 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 розуміє, як викликати службу, з підпису методу та приміток, які ми надали.

To test this client, we can create a JUnit test that uses the embedded server API to run an embedded instance of our server:

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. Programmatic HTTP Client

We also have the option of writing a more traditional client if we need more control over its behavior and implementation:

@Singleton public class ConcreteGreetingClient { private RxHttpClient httpClient; public ConcreteGreetingClient(@Client("/") RxHttpClient httpClient) { this.httpClient = httpClient; } public String greet(String name) { HttpRequest req = HttpRequest.GET("/greet/" + name); return httpClient.retrieve(req).blockingFirst(); } public Single greetAsync(String name) { HttpRequest req = HttpRequest.GET("/async/greet/" + name); return httpClient.retrieve(req).first("An error as occurred"); } }

The default HTTP client uses RxJava, so can easily work with blocking or non-blocking calls.

7. Micronaut CLI

We've already seen the Micronaut CLI tool in action above when we used it to create our sample project.

In our case, we created a standalone application, but it has several other capabilities as well.

7.1. Federation Projects

In Micronaut, a federation is just a group of standalone applications that live under the same directory. By using federations, we can easily manage them together and ensure they get the same defaults and settings.

When we use the CLI tool to generate a federation, it takes all the same arguments as the create-app command. It will create a top-level project structure, and each standalone app will be created in its sub-directory from there.

7.2. Features

When creating a standalone application or federation, we can decide which features our app needs. This helps ensure the minimal set of dependencies is included in the project.

We specify features using the -features argument and supplying a comma-separated list of feature names.

We can find a list of available features by running the following command:

> 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. Existing Projects

We can also use the CLI tool to modify existing projects. Enabling us to create beans, clients, controllers, and more. When we run the mn command from inside an existing project, we'll have a new set of commands available:

> 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. Conclusion

In this brief introduction to Micronaut, we've seen how easy it is to build both blocking and non-blocking HTTP servers and clients. Also, we explored some features of its CLI.

But this is just a small taste of the features it offers. There is also full support for serverless functions, service discovery, distributed tracing, monitoring and metrics, a distributed configuration, and much more.

And while many of its features are derived from existing frameworks such as Grails and Spring, it also has plenty of unique features that help it stand out on its own.

Як завжди, ми можемо знайти наведені вище зразки коду у нашому репозиторії GitHub.