Een Spring Boot-app uitvoeren met Maven versus een uitvoerbare oorlog / jar

1. Inleiding

In deze tutorial onderzoeken we de verschillen tussen het starten van een Spring Boot-webtoepassing via de mvn spring-boot: run commando en het uitvoeren nadat het is gecompileerd in een jar / war-pakket via de java -jar opdracht.

Laten we aannemen dat u al bekend bent met de configuratie van de Spring Boot herverpakken doel. Lees voor meer informatie over dit onderwerp Een Fat Jar-app maken met Spring Boot.

2. De Spring Boot Maven-plug-in

Bij het schrijven van een Spring Boot-applicatie is de Spring Boot Maven-plug-in de aanbevolen tool om onze code te bouwen, testen en verpakken.

Deze plug-in wordt geleverd met veel handige functies, zoals:

  • het lost de juiste afhankelijkheidsversies voor ons op
  • het kan al onze afhankelijkheden (inclusief een embedded applicatieserver indien nodig) verpakken in een enkele, uitvoerbare fat jar / war en zal ook:
    • beheer voor ons de classpath-configuratie, zodat we zo lang kunnen overslaan -cp optie in onze java -jar opdracht
    • implementeer een custom ClassLoader om alle externe jar-bibliotheken te lokaliseren en te laden, die nu in het pakket zijn genest
    • vind automatisch het hoofd() method en configureer het in het manifest, zodat we de hoofdklasse niet hoeven op te geven in onze java -jar opdracht

3. De code uitvoeren met Maven in geëxplodeerde vorm

Wanneer we aan een webtoepassing werken, kunnen we gebruikmaken van een andere zeer interessante functie van het Spring Boot Maven-plug-in: de mogelijkheid om onze webapplicatie automatisch te implementeren in een embedded applicatieserver.

We hebben maar één afhankelijkheid nodig om de plug-in te laten weten dat we Tomcat willen gebruiken om onze code uit te voeren:

 org.springframework.boot spring-boot-starter-web 

Nu, bij het uitvoeren van het mvn spring-boot: run commando in de hoofdmap van het project, leest de plug-in de pom-configuratie en begrijpt dat we een webtoepassingscontainer nodig hebben.

Het uitvoeren van het mvn spring-boot: run commando activeert de download van Apache Tomcat en initialiseert het opstarten van Tomcat.

Laten we het proberen:

$ mvn spring-boot: run ... ... [INFO] ---------------------------------- ------ [INFO] Spring-boot-ops 0.0.1-SNAPSHOT bouwen [INFO] --------------------------- ----- [oorlog] --------------------------------- [INFO] [INFO] >>> spring-boot-maven-plugin: 2.1.3.RELEASE: run (default-cli)> test-compile @ spring-boot-ops >>> Downloaden van central: //repo.maven.apache.org/maven2/org /apache/tomcat/embed/tomcat-embed-core/9.0.16/tomcat-embed-core-9.0.16.pom Gedownload van centraal: //repo.maven.apache.org/maven2/org/apache/tomcat/ embed / tomcat-embed-core / 9.0.16 / tomcat-embed-core-9.0.16.pom (1,8 kB bij 2,8 kB / s) ... ... [INFO] --- spring-boot-maven- plugin: 2.1.3.RELEASE: run (default-cli) @ spring-boot-ops --- ... ... 11: 33: 36.648 [main] INFO oacatalina.core.StandardService - Service starten [Tomcat] 11: 33: 36.649 [main] INFO oacatalina.core.StandardEngine - Servlet-engine starten: [Apache Tomcat / 9.0.16] ... ... 11: 33: 36.952 [main] INFO oaccC [Tomcat]. [Localhost ]. [/] - Initialiseren van Spring em bedded WebApplicationContext ... ... 11: 33: 48.223 [main] INFO oacoyote.http11.Http11NioProtocol - Start ProtocolHandler ["http-nio-8080"] 11: 33: 48.289 [main] INFO osbwetomcat.catTomWebServer - Tomcat gestart op poort (en): 8080 (http) met contextpad '' 11: 33: 48.292 [main] INFO org.baeldung.boot.Application - Applicatie gestart in 22.454 seconden (JVM draait voor 37.692)

Wanneer het logboek de regel toont met ‘Gestarte applicatie ', is onze webapplicatie klaar om te worden opgevraagd via de browser op het adres // localhost: 8080 /

4. De code uitvoeren als een zelfstandige pakketapplicatie

Zodra we de ontwikkelingsfase hebben doorstaan ​​en we verder willen gaan met het in productie nemen van onze applicatie, moeten we onze applicatie verpakken.

Helaas, als we werken met een pot pakket, de basis Maven pakket doel omvat geen van de externe afhankelijkheden.

Dit betekent dat we het alleen als bibliotheek kunnen gebruiken in een groter project.

Om deze beperking te omzeilen,we moeten de Maven Spring Boot-plug-in gebruiken herverpakken doel om onze jar / war als een zelfstandige applicatie uit te voeren.

4.1. Configuratie

Meestal hoeven we alleen de build-plug-in te configureren:

  ... org.springframework.boot spring-boot-maven-plugin ... 

Maar ons voorbeeldproject bevat meer dan één hoofdklasse, dus we moeten Java vertellen welke klasse moet worden uitgevoerd, door ofwel de plug-in te configureren:

 org.springframework.boot spring-boot-maven-plugin com.baeldung.webjar.WebjarsdemoApplication 

of door de begin de les eigendom:

 com.baeldung.webjar.WebjarsdemoApplication 

4.2. De applicatie uitvoeren

Nu kunnen we onze voorbeeldoorlog voeren met twee eenvoudige opdrachten:

$ mvn schoon pakket spring-boot: herverpak $ java -jar target / spring-boot-ops.war

Meer informatie over het uitvoeren van een jar-bestand is te vinden in ons artikel JAR-toepassing uitvoeren met opdrachtregelargumenten.

4.3. In het oorlogsdossier

Om beter te begrijpen hoe de hierboven genoemde opdracht een volledige servertoepassing kan uitvoeren, kunnen we onze spring-boot-ops.war.

Als we het decomprimeren en naar binnen kijken, vinden we de gebruikelijke verdachten:

  • META-INF, met het automatisch gegenereerde MANIFEST.MF
  • WEB-INF / klassen, met daarin onze gecompileerde klassen
  • WEB-INF / lib, die onze oorlogsafhankelijkheden en de ingesloten Tomcat-jar-bestanden bevat

Dat is echter niet alles, want er zijn enkele mappen die specifiek zijn voor onze fat-pakketconfiguratie:

  • WEB-INF / lib-verstrekt, met externe bibliotheken die vereist zijn bij het uitvoeren van embedded, maar niet vereist bij implementatie
  • org / springframework / boot / loader, die de Spring Boot custom class loader bevat - deze bibliotheek is verantwoordelijk voor het laden van onze externe afhankelijkheden en maakt ze toegankelijk tijdens runtime

4.4. Inside the War Manifest

Zoals eerder vermeld, vindt de Maven Spring Boot-plug-in de hoofdklasse en genereert de configuratie die nodig is om het Java opdracht.

Het resultaat MANIFEST.MF heeft een aantal extra regels:

Startklasse: com.baeldung.webjar.Webjarsdemo Toepassing Hoofdklasse: org.springframework.boot.loader.WarLauncher

In het bijzonder kunnen we zien dat de laatste het te gebruiken Spring Boot-laderstartprogramma specificeert.

4.5. In een Jar-bestand

Vanwege de standaard verpakkingsstrategie, onze oorlog verpakking scenario verschilt niet veel, of we het Spring Boot Maven-plug-in of niet.

Om de voordelen van de plug-in beter te kunnen waarderen, kunnen we proberen de pom verpakking configuratie naar pot en loop mvn schoon pakket opnieuw.

We kunnen nu zien dat onze vetpot een beetje anders is georganiseerd dan ons vorige oorlogsdossier:

  • Al onze klassen en bronnenmappen bevinden zich nu onder BOOT-INF / lessen
  • BOOT-INF / lib bevat alle externe bibliotheken

Zonder de plug-in, het lib map zou niet bestaan, en alle inhoud van BOOT-INF / lessen zou zich in de root van het pakket bevinden.

4.6. In het Jar Manifest

Ook de MANIFESTEREN.MF is veranderd, met deze extra regels:

Spring-Boot-Classes: BOOT-INF / classes / Spring-Boot-Lib: BOOT-INF / lib / Spring-Boot-Version: 2.1.3.RELEASE Hoofdklasse: org.springframework.boot.loader.JarLauncher

Spring-Boot-klassen en Spring-Boot-Lib zijn bijzonder interessant, omdat ze ons vertellen waar de klassenlader klassen en externe bibliotheken gaat vinden.

5. Hoe te kiezen

Bij het analyseren van tools, het is absoluut noodzakelijk om rekening te houden met het doel waarvoor deze tools zijn gemaakt. Willen we de ontwikkeling vergemakkelijken of zorgen voor een soepele implementatie en draagbaarheid? Laten we eens kijken naar de fasen die het meest worden beïnvloed door deze keuze.

5.1. Ontwikkeling

Als ontwikkelaars besteden we vaak het grootste deel van onze tijd aan coderen zonder dat we veel tijd hoeven te besteden aan het opzetten van onze omgeving om de code lokaal uit te voeren. Bij eenvoudige toepassingen is dat meestal geen probleem. Maar voor complexere projecten moeten we omgevingsvariabelen instellen, servers starten en databases vullen.

Elke keer dat we de applicatie willen draaien de juiste omgeving configureren, zou erg onpraktisch zijn, vooral als er meer dan één service tegelijkertijd moet draaien.

Dat is waar het uitvoeren van de code met Maven ons helpt. We hebben de hele codebase al lokaal uitgecheckt, dus we kunnen de pom-configuratie en bronbestanden gebruiken. We kunnen omgevingsvariabelen instellen, een in-memory database spawnen en zelfs de juiste serverversie downloaden en onze applicatie implementeren met één opdracht.

Zelfs in een codebase met meerdere modules, waarbij elke module verschillende variabelen en serverversies nodig heeft, kunnen we eenvoudig de juiste omgeving draaien via Maven-profielen.

5.2. Productie

Hoe meer we richting productie gaan, hoe meer het gesprek verschuift naar stabiliteit en veiligheid. Daarom kunnen we het proces dat wordt gebruikt voor onze ontwikkelmachine niet toepassen op een server met live klanten.

De code door Maven laten lopen in dit stadium is om meerdere redenen een slechte gewoonte:

  • Allereerst zouden we Maven moeten installeren
  • Dan, alleen omdat we de code moeten compileren, hebben we de volledige Java Development Kit (JDK) nodig
  • Vervolgens moeten we de codebase naar onze server kopiëren en al onze eigen code in platte tekst achterlaten
  • De mvn commando moet alle fasen van de levenscyclus uitvoeren (bronnen zoeken, compileren en uitvoeren)
  • Dankzij het vorige punt zouden we ook CPU en, in het geval van een cloudserver, geld verspillen
  • Maven spawnt meerdere Java-processen, die elk geheugen gebruiken (standaard gebruiken ze elk dezelfde hoeveelheid geheugen als het bovenliggende proces)
  • Ten slotte, als we meerdere servers moeten implementeren, wordt al het bovenstaande op elke server herhaald

Dit zijn slechts een paar redenen waarom het verzenden van de applicatie als een pakket is praktischer voor de productie.

6. Conclusie

In deze tutorial hebben we de verschillen onderzocht tussen het uitvoeren van onze code via Maven en via het java -jar opdracht. We hebben ook een beknopt overzicht gegeven van enkele praktijkscenario's.

De broncode die in dit artikel wordt gebruikt, is beschikbaar op GitHub.