Quarkus: modernisering av applikationer med exempel pÄ helloworld frÄn JBoss EAP Quickstart

Hej alla i den hÀr bloggen, och hÀr Àr det fjÀrde inlÀgget i serien om Quarkus!

Quarkus: modernisering av applikationer med exempel pÄ helloworld frÄn JBoss EAP Quickstart

Det föregÄende inlÀgget handlade om hur Quarkus förenar MicroProfile och Spring. LÄt oss pÄminna om att Quarkus det positioneras som "super snabb subatomÀr Java", Àven kallad "Kubernetes-orienterad Java-stack, optimerad för GraalVM och OpenJDK HotSpot och byggd med de bÀsta biblioteken och standarderna". Idag ska vi visa hur man moderniserar befintliga Java-applikationer med Quarkus möjligheter, genom exemplet helloworld-applikationen frÄn Red Hat JBoss Enterprise Application Platform (JBoss EAP) Quickstart-repositoriet, dÀr vi anvÀnder teknologier i Quarkus som CDI och Servlet 3.

Det Àr viktigt att notera att bÄde Quarkus och JBoss EAP fokuserar pÄ att anvÀnda verktyg som i största möjliga mÄn Àr byggda pÄ standarder. Har du ingen applikation som kör pÄ JBoss EAP? Inga problem, den kan enkelt flyttas frÄn din nuvarande applikationsserver till JBoss EAP med hjÀlp av Red Hat Application Migration Toolkit. Den slutliga och fungerande versionen av den moderniserade koden kommer att finnas tillgÀnglig i repositoriet github.com/mrizzi/jboss-eap-quickstarts/tree/quarkus, i modulen helloworld.

Vid skrivandet av det hÀr inlÀgget anvÀndes guider för Quarkus, mestadels Creating Your First Application och Building a Native Executable.

HĂ€mta koden

Först skapar vi en lokal klon av repositoriet JBoss EAP quickstarts:

$ git clone https://github.com/jboss-developer/jboss-eap-quickstarts.git
Klonar in i 'jboss-eap-quickstarts'...
remote: Enumrerar objekt: 148133, klart.
remote: Totalt 148133 (delta 0), ÄteranvÀnds 0 (delta 0), pack ÄteranvÀnds 148133
Mottar objekt: 100% (148133/148133), 59.90 MiB | 7.62 MiB/s, klart.
Löser deltar: 100% (66476/66476), klart.
$ cd jboss-eap-quickstarts/helloworld/

Tittar pÄ hur den ursprungliga helloworld fungerar

I grunden Àr syftet med denna applikation tydligt utifrÄn namnet, men vi kommer att modernisera dess kod strikt vetenskapligt. SÄ lÄt oss först titta pÄ denna applikation i sin ursprungliga form.

Starta helloworld

1. Öppna terminalen och gĂ„ till roten av JBoss EAP-mappen (du kan ladda ner den hĂ€r), det vill sĂ€ga i mappen EAP_HOME.

2. Starta JBoss EAP-servern med standardprofilen:

$ EAP_HOME/bin/standalone.sh

AnmÀrkning: för Windows anvÀnds skriptet EAP_HOMEbinstandalone.bat för att starta.

Efter nÄgra sekunder bör loggen visa ungefÀr följande:

[org.jboss.as] (Controller Boot Thread) WFLYSRV0025: JBoss EAP 7.2.0.GA (WildFly Core 6.0.11.Final-redhat-00001) startad pÄ 3315 ms - Startade 306 av 527 tjÀnster (321 tjÀnster Àr lata, passiva eller pÄ begÀran)

3. Öppna i webblĂ€saren 127.0.0.1:8080 och vi ser detta:

Quarkus: modernisering av applikationer med exempel pÄ helloworld frÄn JBoss EAP Quickstart

Fig. 1. Startsidan för JBoss EAP.

4. Följ instruktionerna i guiden Build and Deploy the Quickstart: vi kör igÄng helloworld och kör följande kommando (frÄn projektets rotmapp):

$ mvn clean install wildfly:deploy

Efter att kommandot har körts framgÄngsrikt ser vi ungefÀr följande i loggen:

[INFO] ------------------------------------------------------------------------ 
[INFO] BYGG SUCCÉ 
[INFO] ------------------------------------------------------------------------ 
[INFO] Total tid: 8.224 s

SÄ första distributionen av helloworld-applikationen pÄ JBoss EAP tog lite mer Àn 8 sekunder.

Testar helloworld

Följ noggrant guiden Access the Application, öppnar i webblÀsaren 127.0.0.1:8080/helloworld och ser detta:

Quarkus: modernisering av applikationer med exempel pÄ helloworld frÄn JBoss EAP Quickstart

Fig. 2. Ursprungligt Hello World frÄn JBoss EAP.

Gör Àndringar

Ändrar inparametern createHelloMessage(String name) frĂ„n World till Marco:

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

Kör Äterigen följande kommando:

$ mvn clean install wildfly:deploy

Uppdaterar sedan sidan i webblÀsaren och ser att texten har Àndrats:

Quarkus: modernisering av applikationer med exempel pÄ helloworld frÄn JBoss EAP Quickstart

Fig. 3. Hello Marco i JBoss EAP.

ÅterstĂ€ller distributionen av helloworld och avslutar JBoss EAP

Detta Àr valfritt, men om du vill ÄterstÀlla distributionen kan du göra det med följande kommando:

$ mvn clean install wildfly:undeploy

För att avsluta JBoss EAP-instansen, tryck bara Ctrl+C i terminalfönstret.

Uppgraderar helloworld

Nu ska vi modernisera den ursprungliga helloworld-applikationen.

Skapar en ny gren

Skapar en ny arbetsgren efter att projektet quickstart har slutförts:

$ git checkout -b quarkus 7.2.0.GA

Ändrar filen pom.xml

Vi börjar Àndra applikationen med filen pom.xml. För att Quarkus ska kunna infoga XML-block i den, kör vi följande kommando i helloworld-mappen:

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

Vid tiden för att skriva denna artikel anvÀndes version 0.23.2. Quarkus uppdateras ofta med nya versioner, för att se vilken version som Àr den senaste kan du besöka github.com/quarkusio/quarkus/releases/latest.

OvanstÄende kommando kommer att infoga följande element i pom.xml:

  • Egenskapen , som anger den version av Quarkus som anvĂ€nds.
  • Blocket för att importera Quarkus BOM (bill of materials), sĂ„ att du inte behöver lĂ€gga till versionen för varje Quarkus-beroende.
  • Plugin quarkus-maven-plugin, som ansvarar för att paketera applikationen och erbjuder utvecklingslĂ€ge.
  • Profilen native för att skapa körbara filer av applikationen.

Dessutom gör vi manuellt följande Àndringar i pom.xml:

  1. Flyttar taggen frÄn blocket och placerar den över taggen . Eftersom vi i nÀsta steg kommer att ta bort blocket , mÄste vi spara .
  2. Tar bort blocket , eftersom den hÀr applikationen inte lÀngre behöver en förÀldra-pom frÄn JBoss nÀr man arbetar med Quarkus.
  3. LĂ€gg till taggen och placera den under taggen . Versionsnumret kan anges som du vill.
  4. Ta bort taggen , eftersom denna applikation inte lÀngre Àr en WAR, utan en vanlig JAR.
  5. Modifiera följande beroenden:
    1. Byt ut beroendet javax.enterprise:cdi-api mot io.quarkus:quarkus-arc, ta bort provided, eftersom (enligt dokumentationen) detta Quarkus-tillÀgg tillhandahÄller CDI-beroendeinjektion.
    2. Byt ut beroendet org.jboss.spec.javax.servlet:jboss-servlet-api_4.0_spec mot io.quarkus:quarkus-undertow, ta bort provided, eftersom (enligt dokumentationen) detta Quarkus-tillÀgg ger stöd för servlets.
    3. Ta bort beroendet org.jboss.spec.javax.annotation:jboss-annotations-api_1.3_spec, eftersom det ingÄr i de beroenden vi just har Àndrat.

Versionen av filen pom.xml med alla förÀndringar finns pÄ adressen github.com/mrizzi/jboss-eap-quickstarts/blob/quarkus/helloworld/pom.xml.

Observera att det ovanstÄende kommandot mvn io.quarkus:quarkus-maven-plugin:0.23.2:create inte bara Àndrar filen pom.xml, utan Àven lÀgger till en rad komponenter i projektet, nÀmligen följande filer och mappar:

  • Filen mvnw och mvnw.cmd samt mappen .mvn: Maven Wrapper gör det möjligt att köra Maven-projekt i en viss version av Maven utan att installera den versionen.
  • Mappen docker (i katalogen src/main/): hĂ€r finns exempel pĂ„ Dockerfile-filer för lĂ€gena native och jvm (tillsammans med filen .dockerignore).
  • Mappen resources (i katalogen src/main/): hĂ€r finns en tom fil application.properties och ett exempel pĂ„ startsidan Quarkus index.html (se mer i avsnittet Kör den moderniserade helloworld).

Kör helloworld
För att testa applikationen anvÀnder vi quarkus:dev, som startar Quarkus i utvecklingslÀge (se mer i detta avsnitt i handboken för UtvecklingslÀge).

AnmÀrkning: detta steg kommer förvÀntat att leda till ett fel, eftersom vi inte har gjort alla nödvÀndiga Àndringar Àn.

Nu kör vi kommandot för att se hur det fungerar:

$ .\/mvnw compile quarkus:dev
[INFO] Skanning av projekt...
[INFO]
[INFO] ----------------< org.jboss.eap.quickstarts:helloworld >----------------
[INFO] Bygger Quickstart: helloworld quarkus
[INFO] --------------------------------[ war ]---------------------------------
[INFO]
[INFO] --- maven-resources-plugin:2.6:resources (standard-resurser) @ helloworld ---
[INFO] AnvÀnder 'UTF-8' kodning för att kopiera filtrerade resurser.
[INFO] Kopierar 2 resurser
[INFO]
[INFO] --- maven-compiler-plugin:3.1:compile (standard-kompilering) @ helloworld ---
[INFO] Ingenting att kompilera - alla klasser Àr uppdaterade
[INFO]
[INFO] --- quarkus-maven-plugin:0.23.2:dev (standard-cli) @ helloworld ---
Lyssnar för transport dt_socket pÄ adress: 5005
INFO  [io.qua.dep.QuarkusAugmentor] Börjar quarkus-augmentering
INFO  [org.jbo.threads] JBoss Threads version 3.0.0.Final
ERROR [io.qua.dev.DevModeMain] Kunde inte starta quarkus: java.lang.RuntimeException: io.quarkus.builder.BuildException: Byggfel: Byggningen misslyckades pÄ grund av fel
	[error]: Byggsteget io.quarkus.arc.deployment.ArcProcessor#validate kastade ett undantag: javax.enterprise.inject.spi.DeploymentException: javax.enterprise.inject.UnsatisfiedResolutionException: OtillfredsstÀlld beroende för typ org.jboss.as.quickstarts.helloworld.HelloService och kvalificerare [@Default]
	- java-medlem: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
	- deklarerat pÄ CLASS-bean [typer=[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], kvalificerare=[@Default, @Any], mÄl=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)
Orsakat av: javax.enterprise.inject.UnsatisfiedResolutionException: OtillfredsstÀlld beroende för typ org.jboss.as.quickstarts.helloworld.HelloService och kvalificerare [@Default]
	- java-medlem: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService
	- deklarerat pÄ CLASS-bean [typer=[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], kvalificerare=[@Default, @Any], mÄl=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 mer

SĂ„, det fungerar inte
 Varför?

Undantaget UnsatisfiedResolutionException pekar pÄ klassen HelloService, som Àr en medlem av klassen HelloWorldServlet (java medlem: org.jboss.as.quickstarts.helloworld.HelloWorldServlet#helloService). Problemet Àr att HelloWorldServlet behöver en injicerad instans av HelloService, men den gÄr inte att hitta (Àven om bÄda dessa klasser finns i samma paket).

Det Àr dags att ÄtervÀnda till dokumentationen och lÀsa om hur Inject, och dÀrmed Contexts and Dependency Injection (CDI). SÄ vi öppnar manualen för Contexts and Dependency Injection och lÀser i avsnittet Bean Discovery att: "En bean-klass som inte har nÄgon definierande bean-annotering söks inte."

Tittar pĂ„ klassen HelloService – den har faktiskt ingen sĂ„dan annotering. DĂ€rför mĂ„ste vi lĂ€gga till den sĂ„ att Quarkus kan söka och hitta bean. Eftersom detta Ă€r ett stateless-objekt kan vi helt enkelt lĂ€gga till annoteringen @ApplicationScoped pĂ„ följande sĂ€tt:

@ApplicationScoped
public class HelloService {

AnmÀrkning: hÀr kan utvecklingsmiljön be om att du lÀgger till den erforderliga paketet (se raden nedan), och detta mÄste göras manuellt, sÄ hÀr:

import javax.enterprise.context.ApplicationScoped;

Om du Ă€r osĂ€ker pĂ„ vilken scope du ska anvĂ€nda nĂ€r den ursprungliga bean'en inte alls har definierats, studera dokumentationen JSR 365: Contexts and Dependency Injection for Java 2.0—Standard scope.

Nu försöker vi igen att köra applikationen med kommandot .\/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 gÄr allt utan fel.

Vi kör den uppgraderade helloworld
Som angivet i loggen, öppnar vi i webblÀsaren 0.0.0.0:8080 (standard Quarkus start sida) och ser detta:

Quarkus: modernisering av applikationer med exempel pÄ helloworld frÄn JBoss EAP Quickstart

Fig. 4. Quarkus dev start sida.

I annoteringen WebServlet för denna applikation finns följande kontextdefinition:

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

DÀrför gÄr vi i webblÀsaren till 0.0.0.0:8080/HelloWorld och ser följande:

Quarkus: modernisering av applikationer med exempel pÄ helloworld frÄn JBoss EAP Quickstart

Fig. 5: The Quarkus dev-sidan för Hello World-applikationen.

Och sÄ hÀr, allt fungerar.

Nu gör vi Ă€ndringar i koden. Observera att kommandot ./mvnw compile quarkus:dev fortfarande fungerar, och vi tĂ€nker inte stoppa det. Nu ska vi försöka tillĂ€mpa samma – mycket triviala – Ă€ndringar pĂ„ sjĂ€lva koden och se hur Quarkus underlĂ€ttar livet för utvecklaren:

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

Vi sparar filen och uppdaterar sedan webbsidan för att se meddelandet Hello Marco, som visas pÄ skÀrmdumpen nedan:

Quarkus: modernisering av applikationer med exempel pÄ helloworld frÄn JBoss EAP Quickstart

Fig. 6. Sidan Hello Marco i Quarkus dev.

Nu kontrollerar vi utskriften i terminalen:

INFO  [io.qua.dev] (vert.x-worker-thread-3) Ändrade kĂ€llfiler upptĂ€ckta, kompilera om [/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 stoppades pÄ 0.003s
INFO  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) PÄbörjar quarkus-augmentation
INFO  [io.qua.dep.QuarkusAugmentor] (vert.x-worker-thread-3) Quarkus-augmentation slutförd pÄ 232ms
INFO  [io.quarkus] (vert.x-worker-thread-3) Quarkus 0.23.2 startade pÄ 0.257s. Lyssnar pÄ: http://0.0.0.0:8080
INFO  [io.quarkus] (vert.x-worker-thread-3) Profil dev aktiverad. Live Coding aktiverad.
INFO  [io.quarkus] (vert.x-worker-thread-3) Installerade funktioner: [cdi]
INFO  [io.qua.dev] (vert.x-worker-thread-3) Total tid för varm ersÀttning: 0.371s

Uppdateringen av sidan utlöste upptÀckten av Àndringar i kÀllkoden, och Quarkus utförde automatiskt proceduren "stop-start". Och allt det hÀr utfördes pÄ endast 0.371 sekunder (dÀr har ni, den "super-snabba subatomÀra Java").

Bygger helloworld till JAR-paket
Nu nÀr koden fungerar som den ska, paketerar vi den med följande kommando:

$ ./mvnw clean package

Detta kommando skapar tvĂ„ JAR-filer i mappen /target: filen helloworld-.jar, som Ă€r den standard artefakten som skapats av Maven-kommandot tillsammans med klasser och resurser frĂ„n projektet. Och filen helloworld—runner.jar, som Ă€r en körbar JAR.

Observera att detta inte Àr en uber-jar, eftersom alla beroenden bara kopieras till mappen /target/lib (och inte packas in i JAR-filen). DÀrför, för att köra denna JAR frÄn en annan mapp eller pÄ en annan vÀrd, mÄste bÄde JAR-filen och mappen /lib kopieras dit, med tanke pÄ att Class-Path-elementet i filen MANIFEST.MF i JAR-paketet innehÄller en explicit lista över JAR-filerna frÄn lib-mappen.
För att lÀra dig hur man skapar uber-jars, se guiden Uber-Jar Creation.

Kör helloworld paketerat i JAR

Nu kan vi köra vÄr JAR med det standardkommandot java:

$ java -jar ./target/helloworld--runner.jar
INFO  [io.quarkus] (main) Quarkus 0.23.2 startade pÄ 0.673s. Lyssnar pÄ: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profil prod aktiverad.
INFO  [io.quarkus] (main) Installerade funktioner: [cdi]

NÀr allt detta har slutförts, gÄ in i din webblÀsare pÄ 0.0.0.0:8080 och kolla att allt fungerar som det ska.

Vi bygger helloworld till en inbyggd körbar fil

SÄ, vÄr helloworld fungerar som en fristÄende Java-applikation, med Quarkus beroenden. Men vi kan gÄ lÀngre och omvandla den till en inbyggd körbar fil.

Vi installerar GraalVM
Först mÄste vi installera de nödvÀndiga verktygen:

1. Ladda ner GraalVM 19.2.0.1 frÄn github.com/oracle/graal/releases/tag/vm-19.2.0.1.

2. Packa upp den nedladdade arkivet:

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

3. GĂ„ till untar-mappen.

4. Kör kommandot nedan för att ladda ner och lÀgga till den inbyggda bilden:

$ ./bin/gu install native-image

5. Skriv mappen som skapades i steg 2 i miljövariabeln GRAALVM_HOME:

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

Ytterligare information och installationsinstruktioner för andra OS kan hittas i guiden Bygga en inbyggd körbar fil - FörutsÀttningar.

Vi bygger helloworld till en inbyggd körbar fil
LÀs guiden Bygga en inbyggd körbar fil - Producera en inbyggd körbar fil: "Och nu ska vi skapa en inbyggd körbar fil för vÄr applikation, för att minska uppstartstiden och storleken pÄ disken. Den körbara filen kommer att ha allt som behövs för att köra applikationen, inklusive JVM-maskinen (snarare dess nedskurna version som endast innehÄller det som krÀvs för att köra applikationen) och sjÀlva vÄr applikation."

För att skapa en inbyggd körbar fil mÄste vi aktivera native-profilen i Maven:

$ ./mvnw package -Pnative

VÄr byggning tog en minut och 10 sekunder, och den slutgiltiga filen helloworld-runner skapades i mappen /target.

Vi kör den inbyggda körbara filen helloworld

I det föregÄende steget fick vi den körbara filen /target/helloworld-runner. Nu kör vi den:

$ ./target/helloworld--runner
INFO  [io.quarkus] (main) Quarkus 0.23.2 startade pÄ 0.006s. Lyssnar pÄ: http://0.0.0.0:8080
INFO  [io.quarkus] (main) Profil prod aktiverad.
INFO  [io.quarkus] (main) Installerade funktioner: [cdi]

Öppna igen i webblĂ€saren 0.0.0.0:8080 och kontrollera att allt fungerar som det ska.

FortsÀttning följer!

Vi anser att metoden för att modernisera Java-applikationer med hjÀlp av Quarkus, som diskuterats i detta inlÀgg (Àven om den Àr baserad pÄ ett enkelt exempel), bör tillÀmpas aktivt i verkliga livet. Du kommer troligtvis att stöta pÄ en rad problem, vars lösningar vi delvis kommer att ta upp i nÀsta inlÀgg, dÀr vi kommer att diskutera hur man mÀter minnesanvÀndningen för att utvÀrdera prestandaförbÀttringar, en viktig del av hela moderniseringsprocessen för applikationer.

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster