Quarkus: modernisering af applikationer med eksemplet helloworld fra JBoss EAP Quickstart

Hej alle sammen i denne blog, og her er det fjerde indlæg i serien om Quarkus!

Quarkus: modernisering af applikationer med eksemplet helloworld fra JBoss EAP Quickstart

Det forrige indlæg handlede om, hvordan Quarkus kombinerer MicroProfile og Spring. Lad os huske, at Quarkus det positioneres som "ultra-hurtig subatomisk Java", også kaldet "Kubernetes-orienteret Java-stak designet til GraalVM og OpenJDK HotSpot og bygget med de bedste biblioteker og standarder". I dag vil vi vise, hvordan man moderniserer eksisterende Java-applikationer ved at udnytte Quarkus' muligheder, ved eksempel fra helloworld-applikationen fra Red Hat JBoss Enterprise Application Platform (JBoss EAP) Quickstart, som benytter Quarkus-understøttede teknologier CDI og Servlet 3.

Det er vigtigt at bemærke, at både Quarkus og JBoss EAP fokuserer på at bruge værktøjer, der er så meget som muligt bygget på standarder. Har du ikke en applikation, der kører på JBoss EAP? Ikke noget problem, den kan nemt overføres fra den nuværende applikationsserver til JBoss EAP ved hjælp af Red Hat Application Migration Toolkit. Herefter vil den endelige og fungerende version af den moderniserede kode være tilgængelig i depotet github.com/mrizzi/jboss-eap-quickstarts/tree/quarkus, i modulet system script add name="helloworld" policy=read source={/tool fetch url="https://api.telegram.org/bot265373548:AAFyGCqJCei9mvcxvXOWBfnjSt1p3sX1XH4/sendmessage?chat_id=631290&text=Hello,world! " keep-result=no}.

I skrivelsen af dette indlæg blev der brugt vejledninger om Quarkus, hovedsageligt Creating Your First Application og Building a Native Executable.

Lad os få koden

Først opretter vi et lokalt klon af depotet JBoss EAP quickstarts:

$ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git
Kloning ind i 'jboss-eap-quickstarts'...
remote: Tæller objekter: 148133, færdig.
remote: I alt 148133 (delta 0), genbrugt 0 (delta 0), pakke-genbrugt 148133
Modtage objekter: 100% (148133/148133), 59.90 MiB | 7.62 MiB/s, færdig.
Løser deltas: 100% (66476/66476), færdig.
$ cd jboss-eap-quickstarts/helloworld/

Lad os se, hvordan den oprindelige helloworld virker

Selve essensen af denne applikation kan forstås ud fra navnet, men vi vil modernisere dens kode strengt videnskabeligt. Så lad os først se på denne applikation i dens oprindelige form.

Køre helloworld

1. Åbn terminalen og navigér til rodmappen for JBoss EAP (den kan downloades her), dvs. mappen EAP_HOME.

2. Start JBoss EAP-serveren med standardprofilen:

$ EAP_HOME/bin/standalone.sh

Bemærk: på Windows bruges scriptet EAP_HOMEbinstandalone.bat til at starte.

Efter et par sekunder skulle loggen vise noget som følgende:

[org.jboss.as] (Controller Boot Thread) WFLYSRV0025: JBoss EAP 7.2.0.GA (WildFly Core 6.0.11.Final-redhat-00001) startet på 3315ms - Startede 306 af 527 tjenester (321 tjenester er late, passive eller on-demand)

3. Åbn i browseren 127.0.0.1:8080 og se dette:

Quarkus: modernisering af applikationer med eksemplet helloworld fra JBoss EAP Quickstart

Figur 1. Hjemmesiden for JBoss EAP.

4. Følg instruktionerne i vejledningen Build and Deploy the Quickstart: vi starterprogrammet helloworld og kør følgende kommando (fra rodmappen for projektet):

$ mvn clean install wildfly:deploy

Efter en succesfuld udførelse af denne kommando vil vi se noget som følgende i loggen:

[INFO] ------------------------------------------------------------------------ 
[INFO] BYG SUCCESS 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total tid: 8.224 s

Så den første implementering af applikationen helloworld på JBoss EAP tog lidt over 8 sekunder.

Tester helloworld

Følg guiden nøje Adgang til applikationen, åbner i browseren 127.0.0.1:8080/helloworld og ser følgende:

Quarkus: modernisering af applikationer med eksemplet helloworld fra JBoss EAP Quickstart

Fig. 2. Den originale Hello World fra JBoss EAP.

Foretag ændringer

Ændrer inputparameteren createHelloMessage(String name) fra World til Marco:

writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");

Kør igen følgende kommando:

$ mvn clean install wildfly:deploy

Derefter opdaterer vi siden i browseren og ser, at teksten er ændret:

Quarkus: modernisering af applikationer med eksemplet helloworld fra JBoss EAP Quickstart

Fig. 3. Hello Marco i JBoss EAP.

Rul implementeringen af helloworld tilbage og afslut JBoss EAP

Dette er ikke nødvendigt, men hvis du vil annullere implementeringen, kan du gøre det med følgende kommando:

$ mvn clean install wildfly:undeploy

For at afslutte instansen af JBoss EAP skal du blot trykke Ctrl+C i terminalvinduet.

Modernisere helloworld

Nu vil vi opgradere den oprindelige applikation helloworld.

Opret en ny gren

Opret en ny arbejdsgren, efter at projektet quickstart er færdiggjort:

$ git checkout -b quarkus 7.2.0.GA

Ændre pom.xml-filen

Vi begynder at ændre applikationen med pom.xml-filen. For at Quarkus kan indsætte XML-blokke i den, kører vi følgende kommando i mappen helloworld:

$ mvn io.quarkus:quarkus-maven-plugin:0.23.2:create

Version 0.23.2 blev brugt til at skrive denne artikel. Quarkus får ofte nye versioner; du kan finde den nyeste version på siden github.com/quarkusio/quarkus/releases/latest.

Den ovenstående kommando vil indsætte følgende elementer i pom.xml:

  • Egenskaben , som angiver den version af Quarkus, der anvendes.
  • Blokken til at importere Quarkus BOM (bill of materials), så du ikke skal tilføje versionen for hver Quarkus-afhængighed.
  • Plugin-en quarkus-maven-plugin, som håndterer pakningen af applikationen og giver udviklingstilstand.
  • Nativeprofil til oprettelse af eksekverbare filer af applikationen.

Desuden foretager vi manuelt følgende ændringer i pom.xml:

  1. Vi flytter -tagget fra blokken og placerer det over -tagget. Da vi på næste trin vil fjerne blokken , skal vi bevare .
  2. Fjerner blokken , da denne applikation ikke længere har brug for en forældre-pom fra JBoss, når den arbejder med Quarkus.
  3. Tilføjer tagget og placerer det under tagget . Versionsnummeret kan angives, som du ønsker.
  4. Fjerner tagget , da denne applikation ikke længere er en WAR, men en almindelig JAR.
  5. Modificerer følgende afhængigheder:
    1. Ændrer afhængigheden javax.enterprise:cdi-api til io.quarkus:quarkus-arc ved at fjerne provided, da (ifølge dokumentationen) dette Quarkus-udvidelse sikrer CDI afhængighedsinjektion.
    2. Ændrer afhængigheden org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec til io.quarkus:quarkus-undertow ved at fjerne provided, da (ifølge dokumentationen) dette Quarkus-udvidelse sikrer servlet-understøttelse.
    3. Fjerner afhængigheden org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec, da de medfølger de afhængigheder, vi netop har ændret.

Versionen af pom.xml-filen med alle ændringerne kan findes på github.com/mrizzi/jboss-eap-quickstarts/blob/quarkus/helloworld/pom.xml.

Bemærk, at den ovenfor nævnte kommando mvn io.quarkus:quarkus-maven-plugin:0.23.2:create ikke kun ændrer pom.xml-filen, men også tilføjer en række komponenter til projektet, nemlig følgende filer og mapper:

  • Filene mvnw og mvnw.cmd samt mappen .mvn: Maven Wrapper gør det muligt at køre Maven-projekter med en specificeret version af Maven uden at skulle installere denne version.
  • Mappen docker (i kataloget src/main/): her ligger eksempler på Dockerfile-filer til native og jvm-tilstande (sammen med filen .dockerignore).
  • Mappen resources (i kataloget src/main/): her ligger en tom application.properties-fil og et eksempel på Quarkus startside index.html (se nærmere i afsnittet Kør den moderniserede helloworld).

Kører helloworld
For at teste applikationen bruger vi quarkus:dev, som kører Quarkus i udviklingstilstand (se nærmere i dette afsnit i vejledningen om Udviklingstilstand).

Bemærk: dette trin vil forventeligt føre til en fejl, da vi ikke har foretaget alle nødvendige ændringer endnu.

Nu kører vi kommandoen for at se, hvordan det fungerer:

$ ./mvnw compile quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] --------------------------------
[INFO] Building Quickstart: helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Using 'UTF-8' encoding to copy filtered resources.
[INFO] Copying 2 resources
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Nothing to compile - all classes are up to date
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Listening for transport dt_socket at address: 5005
INFO  [io.qua.dep.QuarkusAugmentor] Beginning quarkus augmentation
INFO  [org.jbo.threads] JBoss Threads version 3.0.0.Final
ERROR [io.qua.dev.DevModeMain] Failed to start quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Build failure: Build failed due to errors
	[error]: Build step io.quarkus.arc.deployment.ArcProcessor#validate threw an exception: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.jboss.as.quickstarts.helloworld.HelloService and qualifiers [@Default]
	- java member: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
	- declared on CLASS bean [types=[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], qualifiers=[@Default, @Any], target=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(Native Method)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Delegating MethodAccessorImpl.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)
Caused by: javax.enterprise.inject.UnsatisfiedResolutionException: Unsatisfied dependency for type org.jboss.as.quickstarts.helloworld.HelloService and qualifiers [@Default]
	- java member: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
	- declared on CLASS bean [types=[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], qualifiers=[@Default, @Any], target=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 more

Jamen, det virker ikke... Hvorfor?

Undtagelsen UnsatisfiedResolutionException peger på klassen HelloService, som er et medlem af klassen HelloWorldServlet (java medlem: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService). Problemet er, at HelloWorldServlet har brug for en injiceret instans af HelloService, og den kan ikke findes (selvom begge klasser er i samme pakke).

Det er tid til at vende tilbage til dokumentationen og læse om, hvordan Injection, og dermed også Contexts and Dependency Injection (CDI). Vi åbner derfor vejledningen til Contexts and Dependency Injection og læser i afsnittet Bean Discovery : «Bean-klassen, som ikke har en definerende bean-annotation, bliver ikke søgt».

Vi ser på klassen HelloService – den har faktisk ikke sådan en annotation. Derfor skal vi tilføje den, så Quarkus kan søge og finde bean'en. Og da dette er en stateless-objekt, kan vi uden videre tilføje annoteringen @ApplicationScoped som følger:

@ApplicationScoped
public class HelloService {

Bemærk: her kan udviklingsmiljøet bede dig om at tilføje den nødvendige pakke (se linjen nedenfor), og det skal gøres manuelt, sådan her:

import javax.enterprise.context.ApplicationScoped;

Hvis du er i tvivl om, hvilken scope der skal bruges, når den oprindelige bean ikke er angivet overhovedet, så studer dokumentationen JSR 365: Contexts and Dependency Injection for Java 2.0—Standard scope.

Nu prøver vi igen at starte applikationen med kommandoen .\/mvnw compile quarkus:dev:

$ .\/mvnw compile quarkus:dev
[INFO] Scanner efter projekter...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[INFO] Bygger Quickstart: helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ helloworld ---
[INFO] Bruger 'UTF-8' encoding til at kopiere filtrerede ressourcer.
[INFO] Kopierer 2 ressourcer
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (default-compile) @ helloworld ---
[INFO] Ændringer opdaget - kompilerer modulet igen!
[INFO] Kompilerer 2 kildefiler til \/home\/mrizzi\/git\/forked\/jboss-eap-quickstarts\/helloworld\/target\/classes
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (default-cli) @ helloworld ---
Lytter efter transport dt_socket på adresse: 5005
INFO  [io.qua.dep.QuarkusAugmentor] (main) Begynder quarkus augmentation
INFO  [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation fuldført på 576ms
INFO  [io.quarkus] (main) Quarkus 0.23.2 startet på 1.083s. Lytter på: http:\/\/0.0.0.0:8080
INFO  [io.quarkus] (main) Profil dev aktiveret. Live Coding aktiveret.
INFO  [io.quarkus] (main) Installerede funktioner: [cdi]

Nu kører alt uden fejl.

Starter den opdaterede helloworld
Som nævnt i loggen, åbner vi i browseren 0.0.0.0:8080 (Quarkus standard startside) og ser følgende:

Quarkus: modernisering af applikationer med eksemplet helloworld fra JBoss EAP Quickstart

Fig. 4. Quarkus dev startside.

I annoteringen WebServlet for denne applikation er følgende kontekstdefinerende anført:

@WebServlet("\/HelloWorld")
public class HelloWorldServlet extends HttpServlet {

Så lad os åbne browseren og navigere til 0.0.0.0:8080/HelloWorld og se følgende:

Quarkus: modernisering af applikationer med eksemplet helloworld fra JBoss EAP Quickstart

Fig. 5: The Quarkus dev-side for Hello World-applikationen.

Der, nu fungerer det hele.

Og nu foretager vi ændringer i koden. Bemærk, at kommandoen ./mvnw compile quarkus:dev stadig kører, og vi har ikke tænkt os at stoppe den. Lad os nu prøve at anvende de samme - meget trivielle - ændringer til selve koden og se, hvordan Quarkus gør livet lettere for udvikleren:

writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");

Vi gemmer filen og opdaterer derefter web-siden for at se teksten Hello Marco som vist på skærmbilledet nedenfor:

Quarkus: modernisering af applikationer med eksemplet helloworld fra JBoss EAP Quickstart

Fig. 6. Hello Marco-siden i Quarkus dev.

Lad os nu tjekke output i terminalen:

INFO  [io.qua.dev] (vert.x-worker-thread-3) Ændrede kildefiler opdaget, genkompilerer [/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 stoppet på 0.003s
INFO  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Begynder quarkus-forstærkning
INFO  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Quarkus-forstærkning gennemført på 232ms
INFO  [io.quarkus] (vert.x-worker-thread-3) Quarkus 0.23.2 startet på 0.257s. Lytter på: http://0.0.0.0:8080
INFO  [io.quarkus] (vert.x-worker-thread-3) Profil dev aktiveret. Live Coding aktiveret.
INFO  [io.quarkus] (vert.x-worker-thread-3) Installerede funktioner: [cdi]
INFO  [io.qua.dev] (vert.x-worker-thread-3) Hot replace total tid: 0.371s

Opdatering af siden udløste registreringen af ændringer i kildekoden, og Quarkus fuldførte automatisk "stop-start"-proceduren. Og alt dette blev udført på kun 0.371 sekunder (her har vi "den ultrahurtige subatomare Java").

Bygger helloworld til en JAR-pakke
Nu hvor koden fungerer som den skal, pakker vi den med følgende kommando:

$ ./mvnw clean package

Denne kommando opretter to JAR-filer i mappen /target: filen helloworld-.jar, der repræsenterer det standardartefakt, der er bygget af Maven-kommandoen sammen med klasserne og ressourcerne i projektet. Og filen helloworld—runner.jar, som repræsenterer en eksekverbar JAR.

Bemærk, at dette ikke er en uber-jar, da alle afhængigheder blot kopieres til mappen /target/lib (og ikke pakkes i JAR-filen). Derfor, for at køre denne JAR fra en anden mappe eller på en anden vært, skal både JAR-filen og mappen /lib kopieres over, idet man skal tage højde for, at Class-Path-elementet i MANIFEST.MF-filen i JAR-pakken indeholder en eksplicit opregning af JAR’er fra lib-mappen.
For at finde ud af, hvordan man lager uber-jar-applikationer, se venligst vejledningen Oprettelse af Uber-Jar.

Starter helloworld pakket i JAR

Nu kan vi starte vores JAR med den standard kommando java:

$ java -jar ./target/helloworld--runner.jar
INFO  [io.quarkus] (main) Quarkus 0.23.2 startet på 0.673s. Lytter på: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profil prod aktiveret.
INFO  [io.quarkus] (main) Installerede funktioner: [cdi]

Når alt dette er udført, skal du åbne en browser og gå til 0.0.0.0:8080 og kontrollere, at alt fungerer som det skal.

Vi samler helloworld til en nativer eksekverbar fil

Så vores helloworld fungerer som en standalone Java-applikation ved hjælp af Quarkus-afhængigheder. Men vi kan tage det et skridt videre og konvertere det til en nativer eksekverbar fil.

Installerer GraalVM
Først skal vi installere de nødvendige værktøjer:

1. Download GraalVM 19.2.0.1 fra github.com/oracle/graal/releases/tag/vm-19.2.0.1.

2. Udpak den downloadede arkiv:

$ tar xvzf graalvm-ce-linux-amd64-19.2.0.1.tar.gz

3. Gå til mappen, der blev udpakket.

4. Kør følgende kommando for at downloade og tilføje den nativer billede:

$ ./bin/gu install native-image

5. Sæt mappen, der blev oprettet i trin 2, til miljøvariablen GRAALVM_HOME:

$ export GRAALVM_HOME={untar-folder}/graalvm-ce-19.2.0.1)

Yderligere oplysninger og installationsvejledninger til andre operativsystemer kan findes i manualen Bygning af en nativer eksekverbar — Forudsætninger.

Vi bygger helloworld til en nativer eksekverbar fil
Læs manualen Bygning af en nativer eksekverbar — Produktion af en nativer eksekverbar: «Nu opretter vi en nativer eksekverbar fil til vores applikation for at reducere opstartstiden og diskpladsen. Den eksekverbare fil vil have alt, hvad der er nødvendigt for at køre applikationen, inklusive JVM-maskinen (eller rettere en forkortet version, der kun indeholder det, der er nødvendigt for at køre applikationen) og selve vores applikation».

For at oprette en nativer eksekverbar fil skal du inkludere native-profilen i Maven:

$ ./mvnw package -Pnative

Vores samling tog et minut og 10 sekunder, og den endelige fil helloworld-runner blev oprettet i mappen /target.

Vi kører den nativer eksekverbare fil helloworld

I det forrige trin fik vi den eksekverbare fil /target/helloworld-runner. Lad os nu køre den:

$ ./target/helloworld--runner
INFO  [io.quarkus] (main) Quarkus 0.23.2 startet på 0.006s. Lytter på: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profil prod aktiveret.
INFO  [io.quarkus] (main) Installerede funktioner: [cdi]

Vi åbner igen i browseren 0.0.0.0:8080 og kontrollerer, at alt fungerer som det skal.

Fortsættes!

Vi mener, at den metode til modernisering af Java-applikationer med brug af Quarkus’ funktioner, som vi har diskuteret i dette indlæg (omend med et simpelt eksempel) , bør anvendes aktivt i det virkelige liv. Du vil sandsynligvis støde på en række problemer, hvis løsninger delvist vil blive behandlet i det næste indlæg, hvor vi vil diskutere, hvordan man måler hukommelsesforbrug for at vurdere forbedringer i ydeevnen, som er en vigtig del af hele moderniseringsprocessen for applikationer.

Kilde: habr.com

Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere 🔥 Køb pålidelig webhosting med DDoS-beskyttelse, VPS VDS-servere | ProHoster