Привет, Хабр!
Micronaut — фреймворк для ЯП Groovy. Он предназначен для создания микросервисов и серверных приложений на JVM. Он был разработан с учетом всех недостатков и ограничений предыдущих фреймворков, таких как Spring и Grails.
В статье рассмотрим, как работать в Groovy с Micronaut на практическом примере.
Начало работы
Для работы с Micronaut требуется JDK версии 17 или выше. Можно загрузить JDK с оф. сайта Oracle или использовать одну из альтернативных дистрибуций, таких как OpenJDK.
После установки JDK желательно проверить, что переменная окружения JAVA_HOME настроена правильно:
export JAVA_HOME=/path/to/your/jdk
export PATH=$JAVA_HOME/bin:$PATH
Micronaut CLI позволяет создавать проекты и управлять ими, установим:
sdk install micronaut
Для юзеров Windows вдобавок стоит установить SDKMAN! и использовать его для установки Micronaut CLI.
Для создания нового проекта Micronaut на Groovy есть команда в Micronaut CLI:
mn create-app example.micronaut.micronautguide --lang=groovy
Команда создаст новый проект с именем example.micronaut.micronautguide, использующий Groovy в качестве основного ЯП.
После создания проекта будет следующая директория и файлы:
example.micronaut.micronautguide
├── build.gradle
├── src
│   ├── main
│   │   ├── groovy
│   │   │   └── example
│   │   │       └── micronaut
│   │   │           └── Application.groovy
│   │   └── resources
│   │       └── application.yml
│   └── test
│       ├── groovy
│       │   └── example
│       │       └── micronaut
│       │           └── ApplicationSpec.groovy
│       └── resources
├── gradle
│   └── wrapper
│       └── gradle-wrapper.properties
└── gradlew
└── gradlew.bat
build.gradle: файл конфигурации Gradle, в котором определяются зависимости и настройки сборки проекта.
src/main/groovy: основная директория для исходного кода на Groovy. Здесь находится главный класс приложения
Application.groovy.src/main/resources: директория для ресурсов приложения, включая файл конфигурации
application.yml.src/test/groovy: директория для тестового кода на Groovy. Здесь находится тестовый класс
ApplicationSpec.groovy.gradle и gradlew: скрипты и конфигурации для сборки проекта с помощью Gradle.
Пошаговое создание микросервиса
Откроем файл build.gradle и там убедимся, что зависимости для Groovy и Micronaut добавлены:
plugins {
    id 'groovy'
    id 'io.micronaut.application' version '3.0.0'
}
version '0.1'
group 'example.micronaut'
repositories {
    mavenCentral()
}
dependencies {
    implementation "io.micronaut:micronaut-runtime"
    implementation "io.micronaut.groovy:micronaut-runtime-groovy"
    testImplementation "io.micronaut.test:micronaut-test-spock"
    testImplementation "org.spockframework:spock-core"
}
micronaut {
    runtime "netty"
    testRuntime "spock"
    processing {
        incremental true
        annotations "example.micronaut.*"
    }
}
Здесь подключаем необходимые плагины и зависимости. Плагин groovy позволяет использовать Groovy в проекте, а io.micronaut.application предоставляет возможности для работы с Micronaut.
Создание основного приложения
Создаем файл src/main/groovy/example/micronaut/Application.groovy:
package example.micronaut
import io.micronaut.runtime.Micronaut
import groovy.transform.CompileStatic
@CompileStatic
class Application {
    static void main(String[] args) {
        Micronaut.run(Application, args)
    }
}
Файл содержит основной класс приложения, который запускает Micronaut. Аннотация @CompileStatic апдейтит производительность за счет статической компиляции Groovy-кода.
Создание контроллера
Создаем контроллер src/main/groovy/example/micronaut/HelloController.groovy:
package example.micronaut
import groovy.transform.CompileStatic
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Produces
import io.micronaut.http.MediaType
@CompileStatic
@Controller("/hello")
class HelloController {
    @Get
    @Produces(MediaType.TEXT_PLAIN)
    String index() {
        "Hello World"
    }
}
Контроллер обрабатывает GET-запросы на /hello и возвращает строку "Hello World". Аннотация @Controller указывает, что этот класс является контроллером, а аннотация @Get указывает, что метод index обрабатывает GET-запросы.
Настроим конфигурацию приложения
Открываем файл src/main/resources/application.yml и добавляем конфигурацию:
micronaut:
  application:
    name: micronautguide
Файл конфигурации задает имя приложения.
Создание теста для контроллера
Создаем файл src/test/groovy/example/micronaut/HelloControllerSpec.groovy:
package example.micronaut
import io.micronaut.http.HttpRequest
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import spock.lang.Specification
import jakarta.inject.Inject
@MicronautTest
class HelloControllerSpec extends Specification {
    @Inject
    @Client("/")
    HttpClient client
    void "test hello world response"() {
        when:
        HttpRequest request = HttpRequest.GET('/hello')
        String rsp = client.toBlocking().retrieve(request)
        then:
        rsp == "Hello World"
    }
}
Тст проверяет, что контроллер возвращает строку "Hello World" при GET-запросе на /hello. Аннотация @MicronautTest указывает, что это тест для Micronaut-приложения.
Добавим новый контроллер для работы с книгами и расширим функционал микросервиса.
Создаем файл src/main/groovy/example/micronaut/BookController.groovy:
package example.micronaut
import groovy.transform.CompileStatic
import io.micronaut.http.annotation.Controller
import io.micronaut.http.annotation.Get
import io.micronaut.http.annotation.Produces
import io.micronaut.http.MediaType
@CompileStatic
@Controller("/books")
class BookController {
    @Get
    @Produces(MediaType.APPLICATION_JSON)
    List<Book> listBooks() {
        [
            new Book("The Stand", "Stephen King"),
            new Book("The Hobbit", "J.R.R. Tolkien")
        ]
    }
}
@CompileStatic
class Book {
    String title
    String author
    Book(String title, String author) {
        this.title = title
        this.author = author
    }
}
Контроллер обрабатывает GET-запросы на /books и возвращает список книг в формате JSON. Также создали класс Book для представления книги.
Создаем файл src/test/groovy/example/micronaut/BookControllerSpec.groovy:
package example.micronaut
import io.micronaut.http.HttpRequest
import io.micronaut.http.client.HttpClient
import io.micronaut.http.client.annotation.Client
import io.micronaut.test.extensions.spock.annotation.MicronautTest
import spock.lang.Specification
import jakarta.inject.Inject
@MicronautTest
class BookControllerSpec extends Specification {
    @Inject
    @Client("/")
    HttpClient client
    void "test list books response"() {
        when:
        HttpRequest request = HttpRequest.GET('/books')
        List books = client.toBlocking().retrieve(request, List)
        then:
        books.size() == 2
        books[0].title == "The Stand"
        books[1].title == "The Hobbit"
    }
}
Тест проверяет, что контроллер возвращает список из двух книг.
Запуск и тестирование приложения
Сборка и запуск приложения:
./gradlew run
Запуск тестов:
./gradlew test
После выполнения всех шагов приложение будет запущено и доступно по адресу http://localhost:8080/hello, возвращая текст "Hello World", а также по адресу http://localhost:8080/books, возвращая список книг. Тесты проверят правильность работы контроллеров.
Micronaut и Groovy — мощное сочетание для создания микросервисов. Подробнее с библиотекой можно ознакомиться здесь.
Материал подготовлен в рамках онлайн‑курса «Groovy Developer».
Комментарии (2)

marknefedov
11.07.2024 04:54Расскажите пожалуйста в чем смысл Groovy? Последний раз я его трогал, только в качестве DSL в Jenkins и как язык он показался достаточно неказистым.
Что он может, что не сделать в том же Kotlin?
          
 
PrinceKorwin
Вот вы показали Hello World на этом фреймворке и он вообще никак не отличается от того, что предлагает Spring / Grails.
Можете показать что это за недостатки и ограничения и как их учел Micronaut?