Ahojte všetci na tomto blogu, a s vami štvrtý príspevok v sérii o Quarkus!

bol o tom, ako Quarkus spája MicroProfile a Spring. Pripomeňme, že sa pozicionuje ako „superrýchla subatomová Java“, teda „Kubernetes-orientovaný Java-stack, optimalizovaný pre GraalVM a OpenJDK HotSpot a postavený z najlepších knižníc a štandardov“. Dnes ukážeme, ako modernizovať už existujúce Java aplikácie využitím možností Quarkus na príklade , v ktorej sú použité technológie podporované v Quarkus, ako CDI a Servlet 3.
Tu je dôležité zdôrazniť, že aj Quarkus, aj JBoss EAP sa zameriavajú na používanie nástrojov, ktoré sú maximálne postavené na základe štandardov. Nemáte aplikáciu bežiacu na JBoss EAP? Žiadny problém, dá sa ľahko presunúť z existujúceho aplikačného servera na JBoss EAP pomocou . Po tom bude finálna a funkčná verzia modernizovaného kódu dostupná v repozitári , v module .
Pri písaní tohto príspevku sa používali , prevažne a Building a .
Získanie kódu
Najprv vytvoríme lokálnu kópiu repozitára :
$ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git
Klonovanie do 'jboss-eap-quickstarts'...
remote: Enumarcia objektov: 148133, hotovo.
remote: Celkom 148133 (delta 0), znovu použité 0 (delta 0), pack-reused 148133
Prijímanie objektov: 100% (148133/148133), 59.90 MiB | 7.62 MiB/s, hotovo.
Riešenie deltas: 100% (66476/66476), hotovo.
$ cd jboss-eap-quickstarts/helloworld/
Pozeráme, ako funguje pôvodný helloworld
Vlastne je podstatou tejto aplikácie zrejmé z názvu, ale kód budeme modernizovať striktne vedecky. Preto sa najprv pozrieme na túto aplikáciu v jej pôvodnej podobe.
Rozbehnite helloworld
1. Otvorte terminál a prejdite do koreňového priečinka JBoss EAP (je možné ho stiahnuť ), teda do priečinka EAP_HOME.
2. Spustite server JBoss EAP s predvoleným profilom:
$ EAP_HOME/bin/standalone.sh
Poznámka: na Windows sa na spustenie používa skript EAP_HOME/bin/standalone.bat.
O niekoľko sekúnd by sa v logu malo objaviť približne toto:
[org.jboss.as] (Controller Boot Thread) WFLYSRV0025: JBoss EAP 7.2.0.GA (WildFly Core 6.0.11.Final-redhat-00001) spustený za 3315 ms - Spustených 306 z 527 služieb (321 služieb je len pasívnych, alebo na vyžiadanie)
3. Otvoríme v prehliadači :8080 a vidíme toto:

Obrázok 1. Domovská stránka JBoss EAP.
4. Postupujte podľa pokynov v príručke : rozbaľujeme helloworld a vykonávame (z koreňového priečinka projektu) nasledujúci príkaz:
$ mvn clean install wildfly:deploy
Po úspešnom vykonaní tohto príkazu v logu uvidíme približne nasledovné:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.224 s
Takže prvé nasadenie aplikácie helloworld na JBoss EAP trvalo niečo viac ako 8 sekúnd.
Testujeme helloworld
Konáme striktne podľa príručky , otvoríme v prehliadači :8080/helloworld a vidíme toto:

Obr. 2. Pôvodný Hello World z JBoss EAP.
Robíme zmeny
Zmeníme vstupný parameter createHelloMessage(String name) z World na Marco:
writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");
Opäť vykonávame nasledujúci príkaz:
$ mvn clean install wildfly:deploy
Potom osviežujeme stránku v prehliadači a vidíme, že text sa zmenil:

Obr. 3. Hello Marco v JBoss EAP.
Zrušíme nasadenie helloworld a ukončíme prácu JBoss EAP
To nie je povinné, ale ak chcete zrušiť nasadenie, môžete to urobiť nasledujúcim príkazom:
$ mvn clean install wildfly:undeploy
Aby ste ukončili inštanciu JBoss EAP, jednoducho stlačte Ctrl+C v okne terminálu.
Modernizujeme helloworld
Teraz sa pustíme do modernizácie pôvodnej aplikácie helloworld.
Vytvárame novú vetvu
Vytvoríme novú pracovnú vetvu po tom, čo sa dokončí vykonanie projektu quickstart:
$ git checkout -b quarkus 7.2.0.GA
Meníme súbor pom.xml
Aplikáciu začneme meniť so súborom pom.xml. Aby Quarkus mohol vkladať do neho XML-bloky, vykonáme nasledujúci príkaz v priečinku helloworld:
$ mvn io.quarkus:quarkus-maven-plugin:0.23.2:create
Pri písaní tohto článku bola použitá verzia 0.23.2. U Quarkus sa často objavujú nové verzie, zistiť, ktorá verzia je najnovšia, môžete na stránke .
Vyššie uvedený príkaz vloží do pom.xml nasledujúce prvky:
- Vlastnosť , ktorá určuje používanú verziu Quarkus.
- Blok na import Quarkus BOM (bill of materials), aby nebolo potrebné pridávať verziu pre každú závislosť Quarkus.
- Plugin quarkus-maven-plugin, ktorý zodpovedá za balenie aplikácie a poskytuje režim vývoja.
- Profil native na vytvorenie spustiteľných súborov aplikácie.
Okrem toho do pom.xml manuálne pridávame nasledujúce zmeny:
- Vytiahneme tag z bloku a umiestnime ho nad tag . Keďže v ďalšom kroku odstránime blok , musíme si zachovať .
- Odstránime blok , pretože táto aplikácia už nebude potrebovať rodičovský pom od JBoss pri práci s Quarkus.
- Pridávame tag a umiestňujeme ho pod tag . Číslo verzie môžete uviesť aké chcete.
- Odstránime tag , pretože táto aplikácia už nie je WAR, ale bežný JAR.
- Modifikujeme nasledujúce závislosti:
- Meníme závislosť javax.enterprise:cdi-api na io.quarkus:quarkus-arc, pričom odstraňujeme provided, pretože (podľa dokumentácie) toto Quarkus rozšírenie zabezpečuje injection závislosti CDI.
- Meníme závislosť org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec na io.quarkus:quarkus-undertow, pričom odstraňujeme provided, pretože (podľa dokumentácie) toto Quarkus rozšírenie zabezpečuje podporu servletov.
- Odstránime závislosť org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec, pretože ich dostaneme s závislosťami, ktoré sme práve zmenili.
Verzia súboru pom.xml so všetkými zmenami sa nachádza na adrese .
Všimnite si, že príkaz mvn io.quarkus:quarkus-maven-plugin:0.23.2:create nielenže mení súbor pom.xml, ale aj pridáva do projektu množstvo komponentov, konkrétne nasledujúce súbory a priečinky:
- Súbor mvnw a mvnw.cmd a priečinok .mvn: Maven Wrapper umožňuje spúšťať projekty Maven určitej verzie Maven bez inštalácie tejto konkrétnej verzie.
- Priečinok docker (v adresári src/main/): tu sa nachádzajú príklady súborov Dockerfile pre režimy native a jvm (spolu so súborom .dockerignore).
- Priečinok resources (v adresári src/main/): tu leží prázdny súbor application.properties a vzorová štartovacia stránka Quarkus index.html (podrobnejšie pozri Spustite modernizované helloworld).
Spúšťame helloworld
Na testovanie aplikácie použijeme quarkus:dev, ktorý spúšťa Quarkus v režime development mode (podrobnejšie pozri túto sekciu v manuáli k ).
Poznámka: tento krok očakávane povedie k chybe, pretože sme neuskutočnili ešte všetky potrebné zmeny.
Teraz spúšťame príkaz, aby sme skontrolovali, ako to bude fungovať:
$ .\/mvnw compile quarkus:dev
[INFO] Skenerovanie projektov...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[INFO] Vytváranie rýchlej inštalácie: helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Používam kódovanie 'UTF-8' na kopírovanie filtrovaných zdrojov.
[INFO] Kopírovanie 2 zdrojov
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Nič sa nemusí kompilovať - všetky triedy sú aktuálne
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Počúvanie na prenos dt_socket na adrese: 5005
INFO [io.qua.dep.QuarkusAugmentor] Začínam augmentáciu quarkus
INFO [org.jbo.threads] JBoss Threads verzia 3.0.0.Final
ERROR [io.qua.dev.DevModeMain] Nepodarilo sa spustiť quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Chyba zostavenia: Zostavenie zlyhalo kvôli chybám
[error]: Krok zostavenia io.quarkus.arc.deployment.ArcProcessor#validate vyhodil výnimku: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Nespokojná závislosť pre typ org.jboss.as.quickstarts.helloworld.HelloService a kvalifikátory [@Default]
- java člen: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
- deklarované na CLASS bean [typy=[javax.servlet.ServletConfig, java.io.Serializable, org.jboss.as.quickstarts.helloworld.HelloWorldServlet, javax.servlet.GenericServlet, javax.servlet.Servlet, java.lang.Object, javax.servlet.http.HttpServlet], kvalifikátory=[@Default, @Any], cieľ=org.jboss.as.quickstarts.helloworld.HelloWorldServlet]
at io.quarkus.arc.processor.BeanDeployment.processErrors(BeanDeployment.java:841)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:214)
at io.quarkus.arc.processor.BeanProcessor.initialize(BeanProcessor.java:106)
at io.quarkus.arc.deployment.ArcProcessor.validate(ArcProcessor.java:249)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at io.quarkus.deployment.ExtensionLoader$1.execute(ExtensionLoader.java:780)
at io.quarkus.builder.BuildContext.run(BuildContext.java:415)
at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2011)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1535)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1426)
at java.lang.Thread.run(Thread.java:748)
at org.jboss.threads.JBossThread.run(JBossThread.java:479)
Spôsobené: javax.enterprise.inject.UnsatisfiedResolutionException: Nespokojná závislosť pre typ org.jboss.as.quickstarts.helloworld.HelloService a kvalifikátory [@Default]
- java člen: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
- deklarované na CLASS bean [typy=[javax.servlet.ServletConfig, java.io.Serializable, org.jboss.as.quickstarts.helloworld.HelloWorldServlet, javax.servlet.GenericServlet, javax.servlet.Servlet, java.lang.Object, javax.servlet.http.HttpServlet], kvalifikátory=[@Default, @Any], cieľ=org.jboss.as.quickstarts.helloworld.HelloWorldServlet]
at io.quarkus.arc.processor.Beans.resolveInjectionPoint(Beans.java:428)
at io.quarkus.arc.processor.BeanInfo.init(BeanInfo.java:371)
at io.quarkus.arc.processor.BeanDeployment.init(BeanDeployment.java:206)
... 14 viac
Takže, nefunguje… A prečo?
Vyžiadanie UnsatisfiedResolutionException ukazuje na triedu HelloService, ktorá je členom triedy HelloWorldServlet (java member: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService). Problém spočíva v tom, že HelloWorldServlet potrebuje injektovanú inštanciu HelloService, ktorú sa nepodarilo nájsť (aj keď sa obe triedy nachádzajú v rovnakom balíku).
Je čas vrátiť sa k a prečítať si, ako v Quarkus funguje , a teda aj (CDI). Preto otvoríme príručku Kontexty a injekcia závislostí a v časti čítame: „Bean trieda, ktorá nemá určujúcu annotáciu bean, sa nehľadá.“
Pozrieme sa na triedu HelloService – skutočne nemá takú anotáciu. Preto ju musíme pridať, aby Quarkus mohol hľadať a nachádzať bean. A keďže ide o stateless objekt, môžeme pridať anotáciu @ApplicationScoped nasledujúcim spôsobom:
@ApplicationScoped
public class HelloService {
Poznámka: tu môže vývojové prostredie požadovať, aby ste pridali požadovaný balík (pozri riadok nižšie), a to bude potrebné urobiť ručne, takto:
import javax.enterprise.context.ApplicationScoped;
Ak si nie ste istí, akú oblasť scope by ste mali použiť, keď pre pôvodný bean nie je vôbec určená, prezrite si dokumentáciu .
Teraz opäť skúšame spustiť aplikáciu príkazom ./mvnw compile quarkus:dev:
$ ./mvnw compile quarkus:dev
[INFO] Skenujem projekty...
[INFO]
[INFO] --------------------------------
[INFO] Skladám Quickstart: helloworld quarkus
[INFO] -------------------------------[ war ]--------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Používam kódovanie 'UTF-8' na kopírovanie filtrovaných zdrojov.
[INFO] Kopírujem 2 zdroje
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Zmeny zistené - prekompilujem modul!
[INFO] Kompilujem 2 zdrojové súbory do /home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/target/classes
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Počúvam prenos dt_socket na adrese: 5005
INFO [io.qua.dep.QuarkusAugmentor] (hlavné) Začínam augmentáciu quarkus
INFO [io.qua.dep.QuarkusAugmentor] (hlavné) Augmentácia quarkus dokončená za 576ms
INFO [io.quarkus] (hlavné) Quarkus 0.23.2 spustené za 1.083s. Počúvam na: http://0.0.0.0:8080
INFO [io.quarkus] (hlavné) Profil dev aktivovaný. Aktívne živé kódovanie.
INFO [io.quarkus] (hlavné) Nainštalované funkcie: [cdi]
Teraz všetko prebieha bez chýb.
Spúšťame vylepšený helloworld
Ako je uvedené v logu, otvoríme v prehliadači :8080 (predvolená domovská stránka Quarkus) a vidíme toto:

Obr. 4. Predvolená domovská stránka Quarkus dev.
V anotácii WebServlet tohto programu je definované nasledujúce kontextové určenie:
@WebServlet("/HelloWorld")
public class HelloWorldServlet extends HttpServlet {
Preto ideme v prehliadači na :8080/HelloWorld a vidíme nasledujúce:

Obr. 5: Stránka The Quarkus dev pre aplikáciu Hello World.
Tak a je to, všetko funguje.
Teraz urobíme zmeny v kóde. Všimnite si, že príkaz ./mvnw compile quarkus:dev stále beží a nemáme v úmysle ho zastaviť. Teraz sa pokúsime aplikovať tie isté – veľmi triviálne – zmeny na samotný kód a pozrieme sa, ako Quarkus uľahčuje život vývojárovi:
writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");
Uložíme súbor a potom aktualizujeme webovú stránku, aby sme videli nápis Hello Marco, ako je znázornené na obrázku nižšie:

Obr. 6. Stránka Hello Marco v Quarkus dev.
Teraz skontrolujeme výstup v termináli:
INFO [io.qua.dev] (vert.x-worker-thread-3) Zistené zmeny zdrojových súborov, prekompilovanie [/home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/src/main/java/org/jboss/as/quickstarts/helloworld/HelloWorldServlet.java]
INFO [io.quarkus] (vert.x-worker-thread-3) Quarkus zastavený za 0.003s
INFO [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Začiatok vylepšenia quarkusu
INFO [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Vylepšenie quarkusu dokončené za 232ms
INFO [io.quarkus] (vert.x-worker-thread-3) Quarkus 0.23.2 spustený za 0.257s. Počúva na: http://0.0.0.0:8080
INFO [io.quarkus] (vert.x-worker-thread-3) Aktivovaný profil dev. Aktivované živé programovanie.
INFO [io.quarkus] (vert.x-worker-thread-3) Nainštalované funkcie: [cdi]
INFO [io.qua.dev] (vert.x-worker-thread-3) Celkový čas horúcej výmeny: 0.371s
Aktualizácia stránky spustila detekciu zmien v zdrojovom kóde a Quarkus automaticky vykonal procedúru "stop-start". A všetko to trvalo len 0.371 sekundy (tu to máte, tú superrýchlu subatomovú Javu).
Vykonávame zostavenie helloworld do balíka JAR
Teraz, keď kód funguje ako má, zabaliť ho nasledujúcim príkazom:
$ ./mvnw clean package
Tento príkaz vytvorí dva JAR súbory v priečinku /target: súbor helloworld-.jar, ktorý predstavuje štandardný artefakt vytvorený príkazom Maven spolu s triedami a zdrojmi projektu. A súbor helloworld—runner.jar, ktorý predstavuje spustiteľný JAR.
Všimnite si, že to nie je uber-jar, pretože všetky závislosti sú jednoducho skopírované do priečinka /target/lib (a nie zabalené do súboru JAR). Preto, aby ste spustili tento JAR z iného priečinka alebo na inom hostiteľovi, musíte skopírovať ako samotný JAR súbor, tak aj priečinok /lib, pričom element Class-Path v súbore MANIFEST.MF v balíku JAR obsahuje explicitný zoznam JAR súborov z priečinka lib.
Aby ste sa dozvedeli, ako vytvárať aplikácie uber-jar, obráťte sa na manuál .
Spúšťame helloworld, zabalený do JAR
Teraz môžeme spustiť náš JAR pomocou štandardného príkazu java:
$ java -jar ./target/helloworld--runner.jar
INFO [io.quarkus] (main) Quarkus 0.23.2 sa začal za 0.673s. Počúva na: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profil prod aktivovaný.
INFO [io.quarkus] (main) Nainštalované funkcie: [cdi]
Po vykonaní všetkých týchto krokov prejdite do prehliadača na :8080 a skontrolujte, či všetko funguje správne.
Skladáme helloworld do natívneho spustiteľného súboru
Takže náš helloworld funguje ako samostatná Java aplikácia s použitím závislostí Quarkus. Môžeme však ísť ďalej a premeniť ho na natívny spustiteľný súbor.
Inštalujeme GraalVM
Predovšetkým je potrebné nainštalovať potrebné nástroje:
1. Stiahnite si GraalVM 19.2.0.1 z .
2. Rozbaľte stiahnutý archív:
$ tar xvzf graalvm-ce-linux-amd64-19.2.0.1.tar.gz
3. Prejdite do rozbalenej zložky.
4. Spustite nižšie uvedený príkaz na stiahnutie a pridanie natívneho obrazu:
$ ./bin/gu install native-image
5. Zadajte zložku vytvorenú v kroku 2 do premennej prostredia GRAALVM_HOME:
$ export GRAALVM_HOME={untar-folder}/graalvm-ce-19.2.0.1)
Ďalšie informácie a inštrukcie na inštaláciu na iných OS nájdete v príručke .
Vykonávame skladanie helloworld do natívneho spustiteľného súboru
Prečítame si príručku : „A teraz vytvoríme natívny spustiteľný súbor pre našu aplikáciu, aby sme skrátili čas jej spustenia a využitie na disku. Spustiteľný súbor bude mať všetko potrebné na spustenie aplikácie, vrátane JVM (respektíve jej skrátenej verzie, ktorá obsahuje len to, čo je potrebné na vykonávanie aplikácie) a našu aplikáciu.“
Na vytvorenie natívneho spustiteľného súboru je potrebné zapnúť natívny profil Maven:
$ ./mvnw package -Pnative
Naša zostava trvala jednu minútu a 10 sekúnd a konečný súbor helloworld-runner bol vytvorený v zložke /target.
Spúšťame natívny spustiteľný súbor helloworld
V predchádzajúcom kroku sme získali spustiteľný súbor /target/helloworld-runner. Teraz ho spustíme:
$ ./target/helloworld--runner
INFO [io.quarkus] (main) Quarkus 0.23.2 sa začal za 0.006s. Počúva na: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profil prod aktivovaný.
INFO [io.quarkus] (main) Nainštalované funkcie: [cdi]
Opäť otvoríme v prehliadači :8080 a skontrolujeme, či všetko funguje správne.
Pokračovanie čoskoro!
Domnie šomáme, že metóda modernizácie aplikácií Java, ktorú sme v tomto príspevku preskúmali (aj keď na jednoduchom príklade) a ktorá využíva funkcie Quarkus, by sa mala aktívne používať v reálnom živote. Pravdepodobne sa pritom stretnete s niekoľkými problémami, ktorých riešenie čiastočne preskúmame v nasledujúcom príspevku, kde sa zameriame na to, ako merať spotrebu pamäte na hodnotenie zlepšenia výkonu, čo je dôležitou súčasťou celého procesu modernizácie aplikácií.
Zdroj: habr.com
