Hallo iedereen op deze blog, hier is het vierde bericht in de Quarkus-serie!

ging over hoe Quarkus MicroProfile en Spring combineert. Laten we dat in herinnering brengen is gepositioneerd als “ultrasnel subatomair Java”, oftewel “Kubernetes-georiënteerde Java-stack, op maat gemaakt voor GraalVM en OpenJDK HotSpot en samengesteld uit de beste bibliotheken en standaarden.” Vandaag zullen we aan de hand van het voorbeeld laten zien hoe u bestaande Java-applicaties kunt moderniseren met behulp van de mogelijkheden van Quarkus , dat gebruikmaakt van CDI- en Servlet 3-technologieën die worden ondersteund door Quarkus.
Het is belangrijk op te merken dat zowel Quarkus als JBoss EAP de nadruk leggen op het gebruik van tools die zo veel mogelijk op standaarden zijn gebaseerd. Heeft u geen applicatie die op JBoss EAP draait? Geen probleem, het kan eenvoudig worden gemigreerd van uw huidige applicatieserver naar JBoss EAP . Daarna zal de definitieve en werkende versie van de gemoderniseerde code beschikbaar zijn in de repository , in de module .
Bij het schrijven van dit bericht hebben we gebruikt , eigenlijk en Gebouw A .
Laten we de code pakken
Laten we eerst een lokale kloon van de repository maken :
$ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git
Cloning into 'jboss-eap-quickstarts'...
remote: Enumerating objects: 148133, done.
remote: Total 148133 (delta 0), reused 0 (delta 0), pack-reused 148133
Receiving objects: 100% (148133/148133), 59.90 MiB | 7.62 MiB/s, done.
Resolving deltas: 100% (66476/66476), done.
$ cd jboss-eap-quickstarts/helloworld/
Laten we eens kijken hoe de originele helloworld werkt
Eigenlijk blijkt de essentie van deze applicatie duidelijk uit de naam, maar we zullen de code strikt wetenschappelijk moderniseren. Laten we daarom eerst deze applicatie in zijn oorspronkelijke vorm bekijken.
Hallo wereld implementeren
1. Open een terminal en ga naar de hoofdmap van de JBoss EAP-map (u kunt deze downloaden ), dat wil zeggen naar de map EAP_HOME.
2. Start de JBoss EAP-server met het standaardprofiel:
$ EAP_HOME/bin/standalone.sh
Opmerking: op Windows Het script EAP_HOMEbinstandalone.bat wordt gebruikt om het programma te starten.
Na een paar seconden zou zoiets in het logboek moeten verschijnen:
[org.jboss.as] (Controller Boot Thread) WFLYSRV0025: JBoss EAP 7.2.0.GA (WildFly Core 6.0.11.Final-redhat-00001) started in 3315ms - Started 306 of 527 services (321 services are lazy, passive or on-demand)
3. Openen in een browser :8080 en we zien dit:

Rijst. 1. JBoss EAP-startpagina.
4. Volg de instructies in de handleiding : vouw helloworld uit en voer (vanuit de hoofdmap van het project) de volgende opdracht uit:
$ mvn clean install wildfly:deploy
Nadat we deze opdracht succesvol hebben uitgevoerd, zien we in het logboek zoiets als het volgende:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 8.224 s
De eerste implementatie van de helloworld-applicatie op JBoss EAP duurde dus iets meer dan 8 seconden.
Hallo wereld testen
Strikt volgens de instructies handelen , openen in de browser :8080/helloworld en we zien dit:

Rijst. 2. Origineel Hello World van JBoss EAP.
Veranderingen maken
Wijzig de invoerparameter createHelloMessage(String name) van World in Marco:
writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");
Voer de volgende opdracht opnieuw uit:
$ mvn clean install wildfly:deploy
Vervolgens vernieuwen we de pagina in de browser en zien we dat de tekst is gewijzigd:

Rijst. 3. Hallo Marco in JBoss EAP.
Draai de helloworld-implementatie terug en sluit JBoss EAP af
Dit is optioneel, maar als u de implementatie wilt annuleren, kunt u dit doen met de volgende opdracht:
$ mvn clean install wildfly:undeploy
Om uw JBoss EAP-instantie af te sluiten, drukt u eenvoudigweg op Ctrl+C in het terminalvenster.
Hallo wereld upgraden
Laten we nu de originele helloworld-applicatie moderniseren.
Maak een nieuwe tak aan
We maken een nieuwe werkvertakking nadat het quickstartproject is voltooid:
$ git checkout -b quarkus 7.2.0.GA
Het pom.xml-bestand wijzigen
We beginnen met het wijzigen van de applicatie vanuit het pom.xml-bestand. Om Quarkus toe te staan XML-blokken erin in te voegen, voert u de volgende opdracht uit in de map helloworld:
$ mvn io.quarkus:quarkus-maven-plugin:0.23.2:create
Bij het schrijven van dit artikel is versie 0.23.2 gebruikt. Quarkus brengt regelmatig nieuwe versies uit, op de website kunt u zien welke versie de nieuwste is .
Met het bovenstaande commando worden de volgende elementen in pom.xml ingevoegd:
- Eigendom , waarin wordt aangegeven welke versie van Quarkus moet worden gebruikt.
- Blok om Quarkus BOM (stuklijst) te importeren, om niet voor elke Quarkus-afhankelijkheid een versie toe te voegen.
- De quarkus-maven-plug-in is verantwoordelijk voor het verpakken van de applicatie en het bieden van de ontwikkelingsmodus.
- Het native profiel voor het maken van uitvoerbare toepassingen.
Daarnaast brengen we handmatig de volgende wijzigingen aan in pom.xml:
- Het label eruit trekken van het blok en plaats deze boven de tag . Omdat we in de volgende stap de blokkade verwijderen , dan moet je opslaan .
- Een blok verwijderen , omdat deze applicatie bij gebruik met Quarkus niet langer een parent-pom van JBoss nodig heeft.
- Voeg een tag toe en plaats deze onder de tag . U kunt het gewenste versienummer opgeven.
- Het label verwijderen , aangezien deze applicatie niet langer een WAR is, maar een gewone JAR.
- We wijzigen de volgende afhankelijkheden:
- Wijzig de afhankelijkheid javax.enterprise:cdi-api in io.quarkus:quarkus-arc en verwijder mits , omdat (volgens de documenten) deze Quarkus-extensie injectie van CDI-afhankelijkheden biedt.
- Wijzig de afhankelijkheid org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec in io.quarkus:quarkus-undertow en verwijder mits , omdat (volgens de documenten) deze Quarkus-extensie ondersteuning biedt voor servlets.
- We verwijderen de org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec-afhankelijkheid, omdat deze wordt geleverd met de afhankelijkheden die we zojuist hebben gewijzigd.
De versie van het pom.xml-bestand met alle wijzigingen bevindt zich op .
Merk op dat de bovenstaande opdracht mvn io.quarkus:quarkus-maven-plugin:0.23.2:create niet alleen het bestand pom.xml wijzigt, maar ook een aantal componenten aan het project toevoegt, namelijk de volgende bestanden en mappen:
- Het bestand mvnw en mvnw.cmd en de map .mvn: Met Maven Wrapper kunt u Maven-projecten van een bepaalde Maven-versie uitvoeren zonder die versie te installeren.
- Docker-map (in de map src/main/): Deze bevat voorbeeld Docker-bestanden voor native en jvm-modi (samen met het .dockerignore-bestand).
- Map Resources (in de map src/main/): Deze bevat een leeg bestand application.properties en een voorbeeld van een Quarkus index.html-startpagina (zie De gemoderniseerde helloworld uitvoeren voor meer details).
Lanceer Hallo Wereld
Om de applicatie te testen gebruiken we quarkus:dev, waarmee Quarkus in de ontwikkelingsmodus wordt gestart (voor meer details, zie dit gedeelte in de handleiding ).
Opmerking: Deze stap zal naar verwachting resulteren in een fout, omdat we nog niet alle noodzakelijke wijzigingen hebben aangebracht.
Laten we nu de opdracht uitvoeren om te zien hoe het werkt:
$ ./mvnw compile quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[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(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)
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
Het werkt dus niet... Waarom?
De UnsatisfiedResolutionException verwijst naar de klasse HelloService, die lid is van de klasse HelloWorldServlet (java-lid: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService). Het probleem is dat HelloWorldServlet een geïnjecteerde instantie van HelloService nodig heeft, en deze kan niet worden gevonden (ook al zitten beide klassen in hetzelfde pakket).
Het is tijd om naar terug te keren en lees hoe het werkt in Quarkus , en daarom (CDI). Open daarom de handleiding Contexten en afhankelijkheidsinjectie en in de sectie lezen we: “Een bonenklasse die geen bonendefiniërende annotatie heeft, wordt niet doorzocht.”
Laten we eens kijken naar de HelloService-klasse: deze heeft echt niet zo'n annotatie. Daarom moet het worden toegevoegd zodat Quarkus de boon kan zoeken en vinden. En aangezien dit een staatloos object is, kunnen we eenvoudig de annotatie @ApplicationScoped als volgt toevoegen:
@ApplicationScoped
public class HelloService {
Opmerking: hier kan de ontwikkelomgeving u vragen om het vereiste pakket toe te voegen (zie onderstaande regel), en u zult dit handmatig moeten doen, zoals dit:
import javax.enterprise.context.ApplicationScoped;
Als u twijfelt over welke scope moet worden gebruikt als deze helemaal niet is gespecificeerd voor de bronbean, lees dan de documentatie .
Nu proberen we opnieuw de applicatie te starten met het commando ./mvnw compile quarkus:dev:
$ ./mvnw compile quarkus:dev
[INFO] Scanning for projects...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[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] Changes detected - recompiling the module!
[INFO] Compiling 2 source files to /home/mrizzi/git/forked/jboss-eap-quickstarts/helloworld/target/classes
[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] (main) Beginning quarkus augmentation
INFO [io.qua.dep.QuarkusAugmentor] (main) Quarkus augmentation completed in 576ms
INFO [io.quarkus] (main) Quarkus 0.23.2 started in 1.083s. Listening on: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profile dev activated. Live Coding activated.
INFO [io.quarkus] (main) Installed features: [cdi]
Nu gaat alles zonder fouten.
Lancering van de gemoderniseerde helloworld
Zoals geschreven in het log, open het in de browser :8080 (de standaard Quarkus-startpagina) en we zien dit:

Rijst. 4. Quarkus dev-startpagina.
De WebServlet-annotatie voor deze toepassing bevat de volgende contextdefinitie:
@WebServlet("/HelloWorld")
public class HelloWorldServlet extends HttpServlet {
Daarom gaan we in de browser naar :8080/HelloWorld en we zien het volgende:

Rijst. 5: De Quarkus-ontwikkelaarspagina voor de Hello World-applicatie.
Nou ja, alles werkt.
Laten we nu wijzigingen in de code aanbrengen. Merk op dat de opdracht ./mvnw compile quakus:dev nog steeds actief is en dat we niet van plan zijn deze te stoppen. Laten we nu proberen dezelfde - zeer triviale - wijzigingen in de code zelf toe te passen en kijken hoe Quarkus het leven gemakkelijker maakt voor de ontwikkelaar:
writer.println("<h1>" + helloService.createHelloMessage("Marco") + "</h1>");
Sla het bestand op en vernieuw vervolgens de webpagina om Hallo Marco te zien, zoals weergegeven in de onderstaande schermafbeelding:

Rijst. 6. Hallo Marco-pagina in Quarkus dev.
Laten we nu de uitvoer in de terminal controleren:
INFO [io.qua.dev] (vert.x-worker-thread-3) Changed source files detected, recompiling [/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 stopped in 0.003s
INFO [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Beginning quarkus augmentation
INFO [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Quarkus augmentation completed in 232ms
INFO [io.quarkus] (vert.x-worker-thread-3) Quarkus 0.23.2 started in 0.257s. Listening on: http://0.0.0.0:8080
INFO [io.quarkus] (vert.x-worker-thread-3) Profile dev activated. Live Coding activated.
INFO [io.quarkus] (vert.x-worker-thread-3) Installed features: [cdi]
INFO [io.qua.dev] (vert.x-worker-thread-3) Hot replace total time: 0.371s
Het vernieuwen van de pagina veroorzaakte de detectie van wijzigingen in de broncode en Quarkus voerde automatisch een stop-startprocedure uit. En dit alles werd voltooid in slechts 0.371 seconden (hier is het, dat “ultrasnelle subatomaire Java”).
Helloworld inbouwen in een JAR-pakket
Nu de code naar behoren werkt, gaan we deze verpakken met de volgende opdracht:
$ ./mvnw clean package
Met deze opdracht worden twee JAR-bestanden gemaakt in de map /target: het helloworld-.jar-bestand, een standaardartefact dat door het Maven-team is samengesteld, samen met de klassen en bronnen van het project. En het helloworld-runner.jar-bestand, een uitvoerbaar JAR-bestand.
Houd er rekening mee dat dit geen uber-jar is, omdat alle afhankelijkheden eenvoudigweg worden gekopieerd naar de map /target/lib (niet verpakt in een JAR-bestand). Om deze JAR vanuit een andere map of op een andere host uit te voeren, moet u daarom zowel het JAR-bestand zelf als de map /lib daarheen kopiëren, aangezien het Class-Path-element in het bestand MANIFEST.MF in het JAR-pakket een expliciete lijst met JAR's uit lib-mappen
Raadpleeg de tutorial voor meer informatie over het maken van uber-jar-applicaties .
Lanceer helloworld verpakt in JAR
Nu kunnen we onze JAR uitvoeren met behulp van de standaard Java-opdracht:
$ java -jar ./target/helloworld-<version>-runner.jar
INFO [io.quarkus] (main) Quarkus 0.23.2 started in 0.673s. Listening on: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profile prod activated.
INFO [io.quarkus] (main) Installed features: [cdi]
Nadat dit allemaal is gedaan, gaat u naar uw browser op :8080 en controleer of alles naar behoren werkt.
Helloworld compileren in een eigen uitvoerbaar bestand
Onze helloworld draait dus als een zelfstandige Java-applicatie met behulp van Quarkus-afhankelijkheden. Maar u kunt verder gaan en er een eigen uitvoerbaar bestand van maken.
GraalVM installeren
Allereerst moet u hiervoor de benodigde hulpmiddelen installeren:
1. Download GraalVM 19.2.0.1 van .
2. Vouw het gedownloade archief uit:
$ tar xvzf graalvm-ce-linux-amd64-19.2.0.1.tar.gz
3. Ga naar de map untar.
4. Voer de onderstaande opdracht uit om de oorspronkelijke afbeelding te downloaden en toe te voegen:
$ ./bin/gu install native-image
5. Registreer de map die in stap 2 is gemaakt in de omgevingsvariabele GRAALVM_HOME:
$ export GRAALVM_HOME={untar-folder}/graalvm-ce-19.2.0.1)
Zie de handleiding voor meer informatie en installatie-instructies voor andere besturingssystemen .
Helloworld inbouwen in een eigen uitvoerbaar bestand
Het lezen van de handleiding : “Laten we nu een eigen uitvoerbaar bestand voor onze applicatie maken om de opstarttijd en schijfgrootte te verminderen. Het uitvoerbare bestand bevat alles wat nodig is om de applicatie uit te voeren, inclusief de JVM (of beter gezegd, een ingekorte versie ervan, die alleen bevat wat nodig is om de applicatie uit te voeren) en onze applicatie zelf.
Om een eigen uitvoerbaar bestand te maken, moet u het oorspronkelijke Maven-profiel inschakelen:
$ ./mvnw package -Pnative
Onze build duurde één minuut en tien seconden en het laatste helloworld-runner f-bestand werd gemaakt in de map /target.
Voer het oorspronkelijke uitvoerbare bestand helloworld uit
In de vorige stap ontvingen we het uitvoerbare bestand /target/helloworld—runner. Laten we het nu uitvoeren:
$ ./target/helloworld-<version>-runner
INFO [io.quarkus] (main) Quarkus 0.23.2 started in 0.006s. Listening on: http://0.0.0.0:8080
INFO [io.quarkus] (main) Profile prod activated.
INFO [io.quarkus] (main) Installed features: [cdi]
Open het opnieuw in de browser :8080 en controleer of alles naar behoren werkt.
Wordt vervolgd!
Wij zijn van mening dat de methode voor het moderniseren van Java-applicaties met behulp van Quarkus-mogelijkheden die in dit bericht wordt besproken (zij het met een eenvoudig voorbeeld) actief in het echte leven zou moeten worden gebruikt. Als je dit doet, zul je waarschijnlijk een aantal problemen tegenkomen, die we gedeeltelijk zullen behandelen in het volgende bericht, waar we zullen praten over hoe je het geheugenverbruik kunt meten om prestatieverbeteringen te beoordelen, een belangrijk onderdeel van het hele moderniseringsproces van applicaties.
Bron: www.habr.com
