Quarkus tips & tricks
Quarkus tips & tricks

В этой статье вы узнаете несколько полезных советов и приемов, связанных с фреймворком Quarkus. Мы сосредоточимся на функциях, которые выделяют Quarkus среди других Java фреймворков. Для тех, кто использует Spring Boot, есть аналогичная статья - Spring Boot Tips, Tricks and Techniques.

Если вы запускаете свои приложения в Kubernetes, то Quarkus, безусловно, будет хорошим выбором в качестве Java фреймворка. У приложений на Quarkus довольно высокая скорость запуска, а также низкое потребление памяти. Вы можете легко скомпилировать своё приложение с помощью GraalVM в нативный бинарный образ. Фреймворк предоставляет множество полезных функций для разработчиков, например, горячая перезагрузка. Я надеюсь, что вы найдете в этой статье советы и приёмы, которые помогут повысить вашу продуктивность при разработке на Quarkus. Или, может быть, это хотя бы убедит вас взглянуть на этот фреймворк, если у вас еще нет опыта работы с ним.

Содержание

  • Совет 1. Используйте командную строку Quarkus

  • Совет 2. Используйте Dev Services при работе с базами данных

  • Совет 3. Используйте упрощенный ORM - Panache

  • Совет 4. Единая конфигурация

  • Совет 5. Развертывание в Kubernetes с Maven

  • Совет 6. Доступ к консоли Dev UI

  • Совет 7. Непрерывное тестирование

  • Совет 8. Собирайте нативные образы с GraalVM в OpenShift

  • Совет 9. Откат транзакции после каждого теста

  • Совет 10. Воспользуйтесь преимуществами поддержки GraphQL

  • Заключение

Я уже публиковал все эти советы в Твиттере в графической форме, показанной ниже. Вы можете получить к ним доступ, используя поиск по хэштегу #QuarkusTips. Я большой поклонник Quarkus (и, честно говоря, Spring Boot тоже :)). Итак, если у вас есть предложения или ваши собственные любимые функции, просто напишите мне в Twitter (@piotr_minkowski). Я обязательно сделаю ретвит вашего твита.

Откат транзакции после каждого теста
Откат транзакции после каждого теста

Совет 1. Используйте командную строку Quarkus

Как сконфигурировать новое приложение при использовании какого-нибудь популярного Java фреймворка? Вы можете перейти на сайт онлайн-генератора, который обычно предоставляется этими фреймворками. Вы слышали о Spring Initializr? Quarkus предлагает аналогичный сайт, доступный по адресу https://code.quarkus.io/. Но, возможно, вы не знаете, что существует также и инструмент Quarkus CLI. Он позволяет создавать проекты, управлять расширениями и выполнять различные команды, необходимые для сборки, тестирования и запуска приложения. Например, вы можете создать исходный шаблон для нового приложения с помощью всего одной команды, как показано ниже.

$ quarkus create app --package-name=pl.piomin.samples.quarkus \
  -x resteasy-jackson,hibernate-orm-panache,jdbc-postgresql \
  -o person-service \
  pl.piomin.samples:person-service

После выполнения этой команды вы увидите такой результат.

Создание исходного шаблона для нового приложения при помощи Quarkus CLI
Создание исходного шаблона для нового приложения при помощи Quarkus CLI

Эта команда создает простое REST приложение, которое использует базу данных PostgreSQL при помощи ORM Quarkus. Кроме того, она задаёт имя приложения, Maven groupId и artifactId. После этого вы можете просто запустить приложение. Для этого перейдите в созданный каталог и выполните следующую команду. В качестве альтернативы вы можете выполнить команду mvn quarkus: dev.

$ quarkus dev

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

Совет 2. Используйте Dev Services при работе с базами данных

Вы слышали о Testcontainers? Это Java-библиотека, которая позволяет автоматически запускать контейнеры во время тестов. Вы можете запускать различные базы данных, Selenium или что угодно еще, что может работать в контейнере Docker. Quarkus обеспечивает встроенную интеграцию с Testcontainers при запуске приложений в режиме разработки или тестирования. Эта функция называется Dev Services. Более того, вам не нужно ничего делать, чтобы её включить. Просто НЕ ПРЕДОСТАВЛЯЙТЕ URL-адрес для подключения к базе данных и учетные данные!

Вернемся к нашему сценарию. Мы уже создали приложение с использованием Quarkus CLI. Оно содержит все необходимые библиотеки. Итак, единственное, что нам теперь нужно сделать, это запустить демон Docker. Благодаря этому Quarkus попытается запустить PostgreSQL с Testcontainers в режиме разработки. Что в итоге? Наше приложение работает и связано с PostgreSQL, запущенным в Docker, как показано ниже.

Итак, мы можем перейти непосредственно к разработке. С помощью команды quarkus dev мы уже включили режим разработки. Благодаря этому мы можем воспользоваться функцией перезагрузки в реальном времени.

Совет 3. Используйте упрощенный ORM - Panache

Давайте добавим немного больше кода в наше приложение. Мы реализуем уровень доступа к данным с помощью Quarkus Panache ORM. Это очень интересный модуль, который фокусируется на том, чтобы сделать создание сущностей модеди данных тривиальным и удобным. Вот наш класс сущности.

@Entity
public class Person extends PanacheEntity {
   public String name;
   public int age;
   @Enumerated(EnumType.STRING)
   public Gender gender;
}

Благодаря тому, что обработкой доступа к полям управляет Quarkus, когда вы обращаетесь к person.name, вы фактически вызываете геттер getName(), и аналогично для записи полей и сеттеров. Это обеспечивает правильную инкапсуляцию во время выполнения, поскольку все обращения к полям будут заменены соответствующими вызовами геттеров или сеттеров. PanacheEntity также заботится о реализации первичного ключа.

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

@ApplicationScoped
public class PersonRepository implements PanacheRepository<Person> {

    public List<Person> findByName(String name) {
        return find("name", name).list();
    }

    public List<Person> findByAgeGreaterThan(int age) {
        return find("age > ?1", age).list();
    }
}

Наконец, давайте добавим класс REST ресурса.

@Path("/persons")
public class PersonResource {

    @Inject
    PersonRepository personRepository;

    @POST
    @Transactional
    public Person addPerson(Person person) {
        personRepository.persist(person);
        return person;
    }

    @GET
    public List<Person> getPersons() {
        return personRepository.listAll();
    }

    @GET
    @Path("/name/{name}")
    public List<Person> getPersonsByName(@PathParam("name") String name) {
        return personRepository.findByName(name);
    }

    @GET
    @Path("/age-greater-than/{age}")
    public List<Person> getPersonsByName(@PathParam("age") int age) {
        return personRepository.findByAgeGreaterThan(age);
    }

    @GET
    @Path("/{id}")
    public Person getPersonById(@PathParam("id") Long id) {
        return personRepository.findById(id);
    }
}

Кроме того, давайте создадим файл import.sql в каталоге src/main/resources. Он содержит SQL команды для создания тестовых записей в базе данных и будет выполнен при запуске Hibernate ORM.

insert into person(id, name, age, gender) values(1, 'John Smith', 25, 'MALE');
insert into person(id, name, age, gender) values(2, 'Paul Walker', 65, 'MALE');
insert into person(id, name, age, gender) values(3, 'Lewis Hamilton', 35, 'MALE');
insert into person(id, name, age, gender) values(4, 'Veronica Jones', 20, 'FEMALE');
insert into person(id, name, age, gender) values(5, 'Anne Brown', 60, 'FEMALE');
insert into person(id, name, age, gender) values(6, 'Felicia Scott', 45, 'FEMALE');

Наконец, мы можем вызвать наш REST сервис.

$ curl http://localhost:8080/persons

Совет 4. Единая конфигурация

Предположим, что мы не хотим запускать базу данных в Docker, тогда мы должны сокнфигурировать соединение в application.properties файле. По умолчанию Quarkus предоставляет 3 профиля: prod, test, dev. Мы можем определить свойства для нескольких профилей внутри одного application.properties, используя синтаксис %{profile-name}.config.name. В нашем случае пусть у нас будет экземпляр базы данных H2, который будет использоваться в 2 профилях - dev и test, и внешний экземпляр PostgreSQL, используемый в профиле prod.

quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=${POSTGRES_USER}
quarkus.datasource.password=${POSTGRES_PASSWORD}
quarkus.datasource.jdbc.url=jdbc:postgresql://person-db:5432/${POSTGRES_DB}

%test.quarkus.datasource.db-kind=h2
%test.quarkus.datasource.username=sa
%test.quarkus.datasource.password=password
%test.quarkus.datasource.jdbc.url=jdbc:h2:mem:testdb

%dev.quarkus.datasource.db-kind=h2
%dev.quarkus.datasource.username=sa
%dev.quarkus.datasource.password=password
%dev.quarkus.datasource.jdbc.url=jdbc:h2:mem:testdb

Перед запуском новой версии приложения мы должны не забыть добавить Maven зависимость для H2 в pom.xml.

<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-jdbc-h2</artifactId>
</dependency>

Вы также можете определить свой собственный профиль и указать свойства, используя его в качестве префикса. А также вы можете определять отдельные файлы конфигурации для конкретного профиля, такие как application-{profile}.properties.

Совет 5. Развертывание в Kubernetes с Maven

Quarkus это фреймворк, который изначально создавался для работы в Kubernetes. Вы можете легко развернуть приложение на Quarkus в кластере Kubernetes, не создавая файлы YAML вручную. Для более сложных конфигураций, например, сопоставления секретов с переменными среды, вы можете использовать application.properties. Для работы с Kubernetes нам нужно включить модуль quarkus-kubernetes. Также есть отдельная реализация для OpenShift.

<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-openshift</artifactId>
</dependency>

После этого Quarkus будет генерировать манифесты развертывания во время сборки при помощи Maven. Мы можем включить автоматическое развертывание в текущий кластер Kubernetes, установив для свойства quarkus.kubernetes.deploy значение true. Для развертывания в OpenShift мы должны изменить цель развертывания по умолчанию с kubernetes на openshift.

quarkus.container-image.build = true
quarkus.kubernetes.deploy = true
quarkus.kubernetes.deployment-target = openshift

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

quarkus.openshift.expose = true
quarkus.openshift.replicas = 2
quarkus.openshift.labels.app = person-app
quarkus.openshift.annotations.app-type = demo
quarkus.openshift.env.mapping.postgres_user.from-secret = person-db
quarkus.openshift.env.mapping.postgres_user.with-key = database-user
quarkus.openshift.env.mapping.postgres_password.from-secret = person-db
quarkus.openshift.env.mapping.postgres_password.with-key = database-password
quarkus.openshift.env.mapping.postgres_db.from-secret = person-db
quarkus.openshift.env.mapping.postgres_db.with-key = database-name

Теперь всё что нам нужно, это просто собрать наше приложение при помощи Maven. В качестве альтернативы мы можем удалить свойство quarkus.kubernetes.deploy из application.properties и включить его в команде Maven.

$ maven clean package -D<meta charset="utf-8">quarkus.kubernetes.deploy=true

Совет 6. Доступ к консоли Dev UI

После запуска Quarkus-приложения в режиме разработки (mvn quarkus: dev) вы можете получить доступ к консоли Dev UI по адресу http://localhost:8080/q/dev. Чем больше модулей вы включите, тем больше параметров вы сможете настроить там. Одна из моих любимых функций - возможность развертывать приложения в OpenShift. Вместо того, чтобы запускать команду Maven для создания приложения, мы можем просто запустить его в режиме разработки и развернуть с помощью графического пользовательского интерфейса.

Развёртывание приложения в OpenShift при помощи Dev UI
Развёртывание приложения в OpenShift при помощи Dev UI

Совет 7. Непрерывное тестирование

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

Давайте добавим несколько тестов для нашего приложения. Во-первых, нам нужно добавить соответствующие зависимости.

<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-junit5</artifactId>
   <scope>test</scope>
</dependency>
<dependency>
   <groupId>io.rest-assured</groupId>
   <artifactId>rest-assured</artifactId>
   <scope>test</scope>
</dependency>

Затем мы добавим несколько простых тестов API. Тестовый класс должен быть помечен аннотацией @QuarkusTest. В остальном реализация типична для библиотеки REST Assured.

@QuarkusTest
public class PersonResourceTests {

    @Test
    void getPersons() {
        List<Person> persons = given().when().get("/persons")
                .then()
                .statusCode(200)
                .extract()
                .body()
                .jsonPath().getList(".", Person.class);
        assertEquals(persons.size(), 6);
    }

    @Test
    void getPersonById() {
        Person person = given()
                .pathParam("id", 1)
                .when().get("/persons/{id}")
                .then()
                .statusCode(200)
                .extract()
                .body().as(Person.class);
        assertNotNull(person);
        assertEquals(1L, person.id);
    }

    @Test
    void newPersonAdd() {
        Person newPerson = new Person();
        newPerson.age = 22;
        newPerson.name = "TestNew";
        newPerson.gender = Gender.FEMALE;
        Person person = given()
                .body(newPerson)
                .contentType(ContentType.JSON)
                .when().post("/persons")
                .then()
                .statusCode(200)
                .extract()
                .body().as(Person.class);
        assertNotNull(person);
        assertNotNull(person.id);
    }
}

Мы также можем запускать эти тесты из консоли Dev UI. Для этого вам следует перейти в консоль Dev UI. Внизу страницы вы найдете модуль тестирования, который отвечает за соответствующую панель. Просто щелкните значок Test result, и вы увидите экран, подобный изображенному ниже.

Совет 8. Собирайте нативные образы с GraalVM в OpenShift

Вы можете легко создать и запустить нативный бинарный образ вашего Quarkus-приложения используя возможности GraalVM в OpenShift. Для этого используйте всего одну команду и конструктор ubi-quarkus-native-s2i. OpenShift создает приложение с использованием подхода S2I (source-2-image). Конечно, вам будет нужен работающий кластер OpenShift (например, локальный CRC или Developer Sandbox https://developers.redhat.com/products/codeready-containers/overview), а также oc - клиент OpenShift, установленный локально.

$ oc new-app --name person-native \
             --context-dir basic-with-db/person-app \
  quay.io/quarkus/ubi-quarkus-native-s2i:21.2-java11~https://github.com/piomin/openshift-quickstart.git

Совет 9. Откат транзакции после каждого теста

Если вам нужно откатить изменения в данных после каждого теста, не делайте этого вручную. Вместо этого вам просто нужно пометить свой тестовый класс при помощи аннотации @TestTransaction. Откат выполняется каждый раз после завершения метода тестирования.

@QuarkusTest
@TestTransaction
public class PersonRepositoryTests {

    @Inject
    PersonRepository personRepository;

    @Test
    void addPerson() {
        Person newPerson = new Person();
        newPerson.age = 22;
        newPerson.name = "TestNew";
        newPerson.gender = Gender.FEMALE;
        personRepository.persist(newPerson);
        Assertions.assertNotNull(newPerson.id);
    }
}

Совет 10. Воспользуйтесь преимуществами поддержки GraphQL

Это последний из советов Quarkus в этой статье. Однако это одна из моих любимых функций Quarkus. Поддержка GraphQL не является сильной стороной Spring Boot. Зато Quarkus предоставляет очень мощные и удобные в использовании расширения для GraphQL для клиентской и серверной сторон.

Во-первых, давайте добавим зависимости Quarkus, отвечающие за поддержку GraphQL.

<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-smallrye-graphql</artifactId>
</dependency>
<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-smallrye-graphql-client</artifactId>
   <scope>test</scope>
</dependency>

Теперь мы можем создать код, отвечающий за предоставление GraphQL API. Класс должен быть помечен аннотацией@GraphQLAPI. Quarkus автоматически генерирует схему GraphQL из исходного кода.

@GraphQLApi
public class EmployeeFetcher {

    private EmployeeRepository repository;

    public EmployeeFetcher(EmployeeRepository repository){
        this.repository = repository;
    }

    @Query("employees")
    public List<Employee> findAll() {
        return repository.listAll();
    }

    @Query("employee")
    public Employee findById(@Name("id") Long id) {
        return repository.findById(id);
    }

    @Query("employeesWithFilter")
    public List<Employee> findWithFilter(@Name("filter") EmployeeFilter filter) {
        return repository.findByCriteria(filter);
    }
}

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

@GraphQLClientApi(configKey = "employee-client")
public interface EmployeeClient {

    List<Employee> employees();
    Employee employee(Long id);
}

Наконец, мы можем добавить простой JUnit тест. Нам нужно всего лишь внедрить EmployeeClient ипользоваться его методами. Если вас интересует более подробная информация о поддержке GraphQL в Quarkus, то прочтите мою статью An Advanced GraphQL with Quarkus.

@QuarkusTest
public class EmployeeFetcherTests {

    @Inject
    EmployeeClient employeeClient;

    @Test
    void fetchAll() {
        List<Employee> employees = employeeClient.employees();
        Assertions.assertEquals(10, employees.size());
    }

    @Test
    void fetchById() {
        Employee employee = employeeClient.employee(10L);
        Assertions.assertNotNull(employee);
    }
}

Заключение

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

От переводчика: если вам интересна тема Quarkus, я приглашаю вас присоединиться к моему телеграм-каналу о Quarkus - https://t.me/quarkusnews.

Комментарии (10)


  1. vsb
    23.10.2021 19:20
    +2

    ИМХО все эти кваркусы, хелидоны да микронавты актуальны ровно до тех пор, пока Spring Native не стабилизируется.

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

    В общем, моё имхо, если вам не жгут эти контейнеры прямо сейчас, подождите ещё пару лет и скомпилируете свои микросервисы на Spring Native.

    Helidon SE в своём роде интересный проект, т.к. он по крайней мере даёт некую приятную минималистичность. Но там всё реактивное, лично я считаю это тупиковым путём. Project Loom сделает всё это ненужным в большинстве случаев.

    Лично я жду появления популярного простенького минималистичного фреймворка, работающего на блокировках, написанного с нуля и включающего опционально нужные мелкие батарейки вроде метрик и тд. Чтобы можно было писать как на Go, условно говоря. Не хватает в Java этой простоты.


    1. gleb_the_human Автор
      23.10.2021 19:55

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

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


    1. grossws
      23.10.2021 21:28
      +1

      Мне лично Quarkus понравился тем что он нацелен на Jakarta EE/MicroProfile, что для тех кто имеет легаси из Java EE мира (или около того) делает миграцию более дешёвой по сравнению со Spring. Заход в cloud-native/cloud-ready там скорее боковая фича по сравнению с build-time резолвингом в их реализации CDI.

      В нашем случае всё оказалось не так просто, гладко и шелковисто, т.к. несмотря на использование EEшных кусков (JAX-RS, Servlet и CDI поверх embedded Jetty, Weld & Resteasy) у нас есть некоторый кусок CDI extensions (который не поддерживается в Quarkus ARC), работа с диспатчингом и контекстами Resteasy и подобные развлечения.

      Но в целом подход Quarkus'а мне понравился. Хотя часть народа удивляется их JAX-RS без Servlet API (там Resteasy+Vert.x+Netty вместо привычных сервлет-контейнеров типа Tomcat/Jetty).

      Для green field разработки можно выбираться что нравится. И текущий Spring Boot вполне удачный конкурент.

      Учитывая что за Quarkus стоит красношляпа -- они имеют все шансы влезть в нишу простого фреймворка для микросервисов и "микролитов" (microlith = microservice/monolith) со стандартно доступными opt-in батарейками типа метрик, трассировок, аггрегации логов, cloud conf, service discovery, load balancing и прочих развлекух.


    1. gleb_the_human Автор
      23.10.2021 23:06
      +1

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

      https://developer.okta.com/blog/2021/06/18/native-java-framework-comparison


  1. isicju
    24.10.2021 10:51
    -1

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


    1. gleb_the_human Автор
      24.10.2021 10:57

      А откуда инфа о купленных джава разрабах?)


      1. isicju
        24.10.2021 11:00

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


        1. gleb_the_human Автор
          24.10.2021 11:36
          +2

          Ради интереса сходил на dzone и посмотрел инфу об авторах пяти первых статей в выдаче поиска по кваркусу - мне ни одного "кваркус активиста" или сотрудника red hat не попалось, в основном, похоже, просто люди, которым интересно попробовать что-то кроме спринга (судя по их статьям и инфе). Так что возможно это какая-то специфика вашего окружения.

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

          Мне кажется кваркус, хелидон и другие набирают популярность за счёт того, что в мире EE это действительно что-то новое. Тех же кто живёт на спринге итак всё устраивает :)


          1. isicju
            24.10.2021 13:04

            https://dzone.com/refcardz/quarkus-1 - первая страница гугла на запрос quarkus dzone - red hat сотрудник

            https://dzone.com/articles/develop-camel-quarkus-applications-using-red-hat-q - red hat

            https://dzone.com/articles/evolution-of-the-quarkus-developer-experience - red hat

            https://dzone.com/articles/simple-quarkus-example-with-cors - red hat

            https://dzone.com/articles/a-java-developers-guide-to-quarkus - red hat

            и это лишь малая часть статей, как вы искали вообще?


            1. gleb_the_human Автор
              24.10.2021 13:54
              +1

              Просто открыл поиск на dzone https://dzone.com/search?page=1 и посмотрел авторов первых пяти статей из результатов :)

              Вообще кроме dzone куча площадок есть ведь. Можете зайти хотя бы на наш сабреддит https://www.reddit.com/r/quarkus/