Рубрики
Без рубрики

Демонстрационное приложение для хипстеров Quarkus

В прошлые выходные я написал статью о создании минимально возможного образа Docker для моего приложения JHipster… Помечены java, quarkus, angular, graalvm.

В прошлые выходные я написал статью о создании минимально возможного образа Docker для моего приложения JHipster . Результатом стало изображение Docker размером 180 Мб, которое запускается в среднем. за 56 секунд в Google Cloud.

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

Объем памяти 59 МБ и время запуска 0,056с 😱 💪🏻

С тех пор, как Red Hat анонсировала Quarkus, я хотел поиграть с этим новым проектом, и сегодня был тот день.

Моя цель в основном состоит в том, чтобы заменить существующее приложение Spring Boot (созданное JHipster) и заменить его собственной версией Quark. Давайте посмотрим, как далеко мы сможем продвинуться.

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

Давайте начнем с первого создания объекта домена событий (Конференции), который имеет поля имени и описания.

package com.devoxx.hipster.domain;

import io.quarkus.hibernate.orm.panache.PanacheEntity;

import javax.persistence.*;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

@Cacheable
@Entity(name = "hipster_event")
public class Event extends PanacheEntity {

    @NotNull@Size(min = 3, max = 100)
    @Column(nullable = false)
    public String name;

    public String description;
}

Hibernate Panache напоминает мне Lombok (не требуются геттеры и сеттеры), и, кроме того, вы также можете использовать проверку bean. С помощью простой аннотации @Cacheable вы можете активировать кэширование Infinispan.

package com.devoxx.hipster.repository;

import com.devoxx.hipster.domain.Event;
import io.quarkus.hibernate.orm.panache.PanacheRepositoryBase;

import javax.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class EventRepository implements PanacheRepositoryBase {

    public Event findByName(String name){
        return find("name", name).firstResult();
    }
}

Методы поиска создаются в репозитории событий. Для моего простого веб-приложения CRUD в настоящее время это всего лишь пример метода. Я надеюсь добавить сюда функции подкачки и сортировки в более поздних версиях.

Базовые объекты домена могут быть переданы непосредственно Angular, но при введении более сложных и конфиденциальных полей (например, электронной почты или секретов OAuth) вы хотите иметь DTO mapper между доменом и пакетом web REST.

MapStruct – это генератор кода, который значительно упрощает реализацию сопоставлений между типами Java bean на основе подхода “соглашение о конфигурации”.

JHipster сильно зависит от MapStruct, поэтому мне нужно было выяснить, возможно ли это с помощью кварков. Фактический веб-сайт Quarks не упоминает об этом но Google действительно предпринял некоторые недавние попытки сделать MapStruct частью экосистемы Quarks, отлично!

package com.devoxx.hipster.service.mapper;

import com.devoxx.hipster.domain.Event;
import com.devoxx.hipster.service.dto.EventDTO;
import org.mapstruct.Mapper;

@Mapper(config = QuarkusMappingConfig.class)
public interface EventMapper {

    EventDTO toDto(Event event);

    Event toEntity(EventDTO eventDTO);
}

Для отображения событий требуется ссылка на интерфейс QuarkusMappingConfig, который сообщает Quarkus, что он использует CDI для внедрения зависимостей. Существует поддержка Spring DI для кварков, но не уверен, что MapStruct уже поддерживает ее?

package com.devoxx.hipster.service.mapper;
import org.mapstruct.MapperConfig;

@MapperConfig(componentModel = "cdi")
interface QuarkusMappingConfig {
}

Модель предметной области, DTO и картографы ВЫПОЛНЕНЫ 👍🏼

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

@ApplicationScoped
public class EventService {

    @Inject
    EventMapper eventMapper;

    /**
     * Get all events.
     *
     * @return list of event DTOs.
     */public List getAll() {
        Stream events = Event.streamAll();
        return events.map(event -> eventMapper.toDto(event) )
                     .collect(Collectors.toList());
    }
}

Конечная услуга также включает в себя код для получения одного конкретного события (по идентификатору) и сохранения В.

@Path("api/events")
@ApplicationScoped
@Produces("application/json")
@Consumes("application/json")
public class EventResource {

    @Inject
    EventService eventService;

//...

    @GETpublic List getEvents() {
        List allEvents = eventService.getAll();

        if (allEvents == null) {
            throw new WebApplicationException("No events available", HttpURLConnection.HTTP_NOT_FOUND);
        }

        return allEvents;
    }

//...
}

Ресурс событий снова не преподнес никаких реальных сюрпризов. Quarks использует RestEasy, и это dip-переключатель, который мне нужно поменять на моей шее после весеннего ОТДЫХА, но я выживу и научусь.

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

Говоря о веселье, Quarks также поддерживает Kotlin. Стоит попробовать это в следующий раз.

@QuarkusTest
class EventEndpointTest {

    @Test
    void testGetOneEvent() {
        given()
                .when().get("/api/events/1")
                .then()
                .statusCode(HttpURLConnection.HTTP_OK)
                .assertThat()
                .body(containsString("Devoxx"),
                      containsString("for developers"));

    }

    @Test
    void testGetAllEvents() {
        //List all, the database has initially 2 events
        given()
                .when().get("/api/events")
                .then()
                .statusCode(HttpURLConnection.HTTP_OK)
                .assertThat()
                .body("size()", is(2));

    }
}

JHipster использует Liquibase, но Quarkus (пока) поддерживает только FlyWay (Аксель, спасибо за приглашение, но у меня уже болит голова от одного взгляда на beer 🤪 ).

Рядом с добавлением зависимости FlyWay maven вам необходимо активировать ее, добавив следующую строку в файл application.properties.

# Flyway minimal config properties
quarkus.flyway.migrate-at-start=true

Затем в каталог resources/db/migration вы добавляете инструкции SQL. Не забудьте добавить генератор последовательностей PostgreSQL, иначе новые объекты домена не получат никаких идентификаторов.

CREATE SEQUENCE hibernate_sequence START 10;

CREATE TABLE hipster_event
(
    id   INT,
    name VARCHAR(100),
    description VARCHAR(255)
);
INSERT INTO hipster_event(id, name, description)
VALUES (1, 'Devoxx Belgium 2019', 'The developers conference from developers for developers'),
       (2, 'Devoxx UK 2019', 'The developers conference in London');

Теперь, когда у нас есть вся логика, давайте посмотрим, как мы можем управлять этим ребенком.

Вам необходимо загрузить Graal VM 1.0 rc16 и Apache Maven 3.5.3+.

Примечание: GraalVM v19.0 еще не поддерживается Quarkus, но, похоже, команда Red Hat работает над ним @ Примечание: GraalVM v19.0 еще не поддерживается Quarkus, но, похоже, команда Red Hat работает над ним @

После того, как проект был скомпилирован и упакован maven, теперь вы можете запустить приложение Quarks:

$ mvn quarkus:dev

Что действительно здорово, так это то, что Quarks поддерживает горячую перезагрузку проекта. Всякий раз, когда HTTP-запрос попадает в приложение, оно перезагружает приложение, поскольку это занимает всего несколько миллисекунд. Наконец, возможность горячей перезагрузки без настройки Zeroturnaround JRebel – очень приятный бонус.

Наиболее важные результаты перечислены ниже…

INFO  [io.qua.dep.QuarkusAugmentor] (main) Beginning quarkus augmentation
INFO  [io.qua.fly.FlywayProcessor] (build-6) Adding application migrations in path: file:/Users/stephan/java/projects/quarkushipster/backend/target/classes/db/migration/
INFO  [io.qua.fly.FlywayProcessor] (build-6) Adding application migrations in path: file:/Users/stephan/java/projects/quarkushipster/backend/target/classes/db/migration
INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 703ms
INFO  [org.fly.cor.int.lic.VersionPrinter] (main) Flyway Community Edition 5.2.4 by Boxfuse
INFO  [org.fly.cor.int.dat.DatabaseFactory] (main) Database: jdbc:postgresql:quarkus_hipster (PostgreSQL 10.5)
INFO  [org.fly.cor.int.com.DbValidate] (main) Successfully validated 1 migration (execution time 00:00.013s)
INFO  [org.fly.cor.int.sch.JdbcTableSchemaHistory] (main) Creating Schema History table: "public"."flyway_schema_history"
INFO  [org.fly.cor.int.com.DbMigrate] (main) Current version of schema "public": << Empty Schema >>
INFO  [org.fly.cor.int.com.DbMigrate] (main) Migrating schema "public" to version 1.0.0 - HIPSTER
INFO  [org.fly.cor.int.com.DbMigrate] (main) Successfully applied 1 migration to schema "public" (execution time 00:00.050s)
INFO  [io.quarkus] (main) Quarkus 0.15.0 started in 1.781s. Listening on: http://[::]:8080
INFO  [io.quarkus] (main) Installed features: [agroal, cdi, flyway, hibernate-orm, jdbc-postgresql, narayana-jta, resteasy, resteasy-jsonb]

Ооооооооо Кваркус запустил мое простое Java-приложение CRUD за 1.781 секунды.

Quarkus 0.15.0 стартовал за 1.781секунды.

И он еще даже не работает в собственном режиме 😱

Прежде чем вы сможете создать собственный пакет, вам необходимо установить Graal VM native-image tool. Измените каталог оболочки на каталог Graal VM bin и введите следующее:

$ gu install native-image

Теперь вы можете создать собственный образ Java-приложения, для которого потребуется несколько твитов и один кофе (около 3 минут в зависимости от вашего компьютера).

$ mvn package -Dnative

Команда maven создаст приложение {project}{version}-runner в целевом каталоге. Вы можете просто запустить приложение, выполнив его в командной оболочке.

Родное приложение впервые запустилось “только” примерно через 5056 секунд, но, похоже, мне пришлось обновить свой/etc/hosts и добавить свое имя хоста в localhost.

127.0.0.1       localhost   Stephans-MacBook-Pro.local
::1             localhost   Stephans-MacBook-Pro.local

Как только это было добавлено, собственное приложение запустилось за 0,056 секунды, как показано ниже, и размер приложения составляет всего 56 МБ. 😱

Сначала пришлось немного расслабиться после шока от скорости, но теперь давайте создадим приложение Angular 7 с помощью JHipster.

Клиент-хипстер

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

$ jhipster --skip-server

После создания мы теперь можем импортировать файл JDL (Hipster Domain Language), который создаст все связанные страницы Angular CRUD и логику. В текущем JDL есть только модель домена событий с двумя полями: имя и описание.

$ jhipster import-jdl jhipster.jdl 

Это слишком просто, предыдущая команда создает современный код Angular TypeScript менее чем за 5 минут. Среднестатистическому разработчику потребовался бы день (или больше), чтобы сделать это, и, вероятно, выставить счет клиенту за одну неделю!

Вы запускаете веб-приложение Angular Hipster с помощью npm start, а затем открываете свой браузер и указываете на http://localhost:9000

Это то, что вы получаете:

Чтобы показать данные о событиях конференции, мне пришлось реализовать несколько макетных конечных точек REST в Quarkus для аутентификации пользователя и сведений об учетной записи.

Я также отключил полномочия ROLE_USER в файле event.route.ts, поскольку это еще не настроено.

Как только эти изменения были внесены, я мог наслаждаться своей ГРУБОЙ логикой …. эй, подождите… что? Черт… браузеру не нравится получать доступ к порту 9000 и получать доступ к ОСТАЛЬНЫМ внутренним конечным точкам на порту 8080. Совместное использование ресурсов из разных источников (CORS).

Хм, как Кваркус справится с КОРСОМ?

Google указал мне на пример CorsFilter, который я должен был добавить в проект Quarkus, и это сработало, отлично!

Теперь у нас есть (не защищенный) Веб-приложение Angular, созданное JHipster и взаимодействующее с серверной частью Quark u.s. со временем запуска менее 2 секунд и горячей перезагрузкой как веб-, так и java-модулей.

Еще один дождливый уик-энд должен позволить мне добавить RBAC & JWT (который поддерживает Quarks), но тем временем вы можете проверить проект с

devoxx/quarkusHipster

Это базовое хипстерское приложение Angular CRUD, использующее Quarks в качестве серверной службы.

Ознакомьтесь также с моей связанной статьей LinkedIn .

Внутренний код очень прост и использует следующие кварки (расширения):

  • БУДЬТЕ спокойны, чтобы выставить конечные точки REST
  • Спящий режим ORM с помощью Panache для выполнения операций CRUD с базой данных
  • MapStruct для отображения DTO
  • Контроль версий FlyWay для таблиц базы данных
  • ArC, инструмент внедрения зависимостей, вдохновленный CDI, с нулевыми накладными расходами
  • Высокопроизводительный пул соединений Agroal
  • Кэширование на основе Infinispan
  • Все надежно координируется менеджером транзакций Нараяны
  • База данных PostgreSQL ; смотрите ниже, чтобы запустить его через Docker

Это демонстрационное приложение основано на примере проекта Quarkus “hibernate-orm-panache-resteasy”, предоставленного командой Red Hat @ Это демонстрационное приложение основано на примере проекта Quarkus “hibernate-orm-panache-resteasy”, предоставленного командой Red Hat @

Спасибо командам Quarkus (Red Hat), Hipster, GraalVM за их потрясающую работу!

Требования

Чтобы скомпилировать и запустить эту демонстрационную версию, вам понадобится:

  • GraalVM 1.0 rc16
  • Апач…

Или на GitLab @ Или на GitLab @

Я принимаю запросы на слияние 😎 👍🏼

Еще раз спасибо командам Graal VM, Quarks и JHipster за то, что сделали это волшебство возможным!

После публикации статьи я получил несколько интересных отзывов в Твиттере, похоже, время запуска все еще слишком медленно 😎

Я должен получать около 0,015 с в собственном режиме, но по какой-то неизвестной причине (разрешение DNS?) мое родное приложение запускается только через 5 секунд. По словам Эммануэля, это может быть связано с некоторым медленным/недоступным разрешением DNS.

Вышеуказанная проблема была решена путем добавления моего имени хоста к localhost в/etc/hosts!!

Вы можете следить за соответствующим обсуждением на моей временной шкале Twitter.

Оригинал: “https://dev.to/stephan007/the-jhipster-quarkus-demo-app-1a1n”