Pagina „Maven” trimite aici. Pentru sonda spațială vedeți MAVEN.

Maven este un sistem de build și administrare a proiectelor, scris în Java. Face parte din proiectele găzduite de Apache Software Foundation. Funcționalitățile sale principale sunt descrierea procesului de build al software-ului și descrierea dependențelor acestuia. Proiectele sunt descrise printr-unul sau mai multe fișier XML, denumite POM-uri (Project Object Model), dar au o structură implicită, ceea ce încurajează structurarea similară a proiectelor. POM-ul principal conține informații despre module, precum și despre dependențele proiectului (alte proiecte). Ordinea operațiunilor de build este definită prin declararea unor pluginuri folosite, din cadrul cărora unele goaluri sunt plasate și configurate în diferitele faze predefinite din ciclul de viață al unui build. Maven descarcă dinamic bibliotecile Java si pluginurile, din unul sau mai multe repository-uri.

Concepte de bază

modificare

Conceptul central în Maven este acela de POM (Project Object Model), un document XML care descrie un proiect sau un modul al acestuia. Proiectele multimodulare au un POM pentru fiecare modul, precum și un POM general care le agregă. În mod minimal, POMul unui proiect îi definește o denumire unică (formată din groupId și artifactId) și o versiune. Componentele denumirilor trebuie să asigure unicitate proiectului, astfel că s-a răspândit pe scară largă convenția ca groupId să fie inversul unui nume complet calificat de domeniu, la care se adaugă elemente comune unui set de proiecte ale persoanei sau firmei care le dezvoltă, similar cu numele package-ului în care sunt grupate clasele Java. groupId poate fi sau nu identic cu un package părinte al claselor din proiect.

Un proiect care definite aceste denumiri și versiunea este un proiect minimal pe care Maven îl poate builda fără alte elemente de bază, inferând toate celelalte configurații necesare din convenții, implementate într-un așa-numit „Super POM”. Proiectele din viața reală mai au însă și alte elemente incluse în POM, care completează sau suprascriu unele configurații ale Super POM-ului.

Pentru un proiect Java, convențiile sunt acelea de a compila toate sursele din subdirectorul src/main/java, de a alătura fișierelor bytecode rezultate toate fișierele din src/main/resources și apoi de a le arhiva într-un fișier cu extensia jar. Se compilează apoi testele automate definite în src/test/java și se rulează având în classpath și resursele statice (fișierele) din src/test/resources. Dacă toți pașii au reușit, la final, în subdirectorul target al directorului proiectului va apărea fișierul artifactId-version.jar.

Relațiile părinte-copil și modul-submodul

modificare

Relația între POMul unui modul și „Super POMul” implicit se manifestă prin faptul că POMul moștenește de la Super POM un set de configurații, pe care nu mai are nevoie să le definească. Se pot însă defini niveluri intermediare de POMuri, definite apoi ca „părinte” al POMului de proiect/modul. Asemenea POM-uri pot servi, de exemplu, la sincronizarea unor configurații, sau ale versiunilor dependențelor mai multor proiecte elaborate în cadrul aceleiași organizații și la simplificarea actualizării lor în mai multe proiecte simultan.

În afara moștenirii, un POM-părinte poate face și agregarea mai multor module într-un proiect. Relația modul-submodul este similară celei părinte-copil, cu adăugirea faptului că și modulul va ști ce submodule există, ele fiind declarate în cadrul POMului său. Modulul servește în continuare drept părinte pentru submodule, dar are în mod obligatoriu declarat packaging ca pom. Astfel, la buildarea modulului, se va invoca buildarea tuturor submodulelor, în timp ce modulul nu va produce un artifact, expunându-și în schimb numai POMul.

Dependențele și repositories

modificare

Una din facilitățile pentru care a fost dezvoltat Maven de la bun început, ca software diferit de celălalt proiect al Fundației Apache dedicat buildurilor, Ant, l-a constituit gestiunea dependențelor. Proiectele care depind de alte biblioteci puneau probleme mari de gestiune a acestor dependențe: întreținerea classpath-urilor diferite la compilare, rulare, compilare de teste și rulare de teste, la care se adăuga problema dependențelor tranzitive: biblioteci care depind de alte biblioteci de care depind alte biblioteci, într-un arbore cu adâncime care poate fi mare și a cărui integritate (versiunile corecte, eliminarea duplicatelor și a versiunilor diferite ale aceleiași biblioteci din arborele de dependențe) putea deveni un coșmar. Astfel, Maven a fost construit în jurul acestui concept, că fiecare modul produce după build un așa-numit artifact. Artifactul este un fișier care împachetează codul livrabil al modulului, care poate fi reutilizat mai departe de alte module.

Artifactele se produc, în urma compilării și apoi împachetării, implicit în subdirectorul target al directorului de build, și ulterior se depun într-un repository, o structură de directoare din care aceste artifacte pot fi recuperate automat pe baza unor reguli convenționale. Maven depune apoi artifactele într-un astfel de repository local (creând, dacă este nevoie, calea directorului în care se pune el), iar maven va folosi acest artifact atunci când este adresat prin groupId, artifactId și versiune, de alte builduri Maven sau alte software-uri capabile să navigheze structura unui repository Maven. Fișierele pot fi însă depuse și în repository-uri comune mai mari, stocate în rețea și accesibile prin HTTP, ca de exemplu un repository al unei companii de dezvoltare sau al unei organizații. Fundația Apache furnizează un astfel de repository implicit la adresa https://mvnrepository.com/ Arhivat în , la Wayback Machine. unde sunt stocate biblioteci reutilizabile pe scară largă; el este disponibil oricărei instalări de Maven fără configurări speciale; setările locale ale instalării de Maven, sau setările din POMul unui proiect pot face referire la alte repositories. Există software-uri specializate în menținerea de astfel de repositories, cum ar fi Sonatype Nexus sau JFrog Artifactory, care stochează artifactele, expunându-și baza de date de artifacte sub mai multe formate, inclusiv cel de repository Maven.

Când i se cere un artifact dependent de modulul buildat, Maven este capabil să identifice dependențele tranzitive și să includă toate bibliotecile care depind de cea cerută. Dacă există dependențe care se folosesc doar la anumite operațiuni (de exemplu, cele pentru teste sau necesare doar pentru compilare), ele se pot declara împreună cu un scope care oferă lui Maven această informație; artifactele astfel declarate se folosesc doar în momentele la care este nevoie. Scope-urile principale sunt compile (cel implicit, care înseamnă că artifactul este prezent în toate etapele); runtime (artifacte care trebuie să fie prezente la rulare și testare, dar nu și la compilare — de exemplu, implementări ale API-urilor folosite); provided (similar cu runtime, artifacte despre care există așteptarea că vor exista la rulare, dar care urmează să fie furnizate de către containerul care rulează aplicația sau de către JDK); și test (artifacte necesare testării codului, care însă nu trebuie distribuite și nu sunt necesare la rulare). Alte două scope-uri (system și import) sunt disponibile pentru unele cazuri speciale, mai rare.

Un modul produce în mod implicit un singur artifact, cel ce cuprinde toate clasele sub formă de bytecode Java executabil; dar există configurări ale POMului prin care buildul poate produce mai multe artifacte dedicate mai multor scopuri: un artifact de surse pentru distribuirea surselor unui proiect cu sursă deschisă, un artifact de documentație, eventual artifacte diferite dedicate diferitelor platforme.

Ciclul de viață al buildului și pluginurile

modificare

Dezvoltatorii proiectului s-au distanțat de modelul folosit în proiectul Ant, acela de folosire a XML-ului pentru controlul fluxului de execuție, optând în același timp pentru o arhitectură extensibilă, în care toată funcționalitatea se află în pluginuri predefinite, cărora li se pot adăuga alte pluginuri dezvoltate de utilizatori. Pluginurile sunt unități dezvoltate individual și disponibile în repository-ul Maven ca artifacte. Ele expun niște goaluri (în traducere liberă, „țeluri”), care reprezintă comenzi ce pot fi date pluginului, fiecare cu o anume configurație.

Fluxul de execuție este unul prestabilit, în etape succesive denumite faze, care împreună alcătuiesc ciclul de viață al buildului. Ciclul de viață implicit cuprinde 23 de faze care definesc etape prezente în procesele de build, cum ar fi validarea surselor, inițializarea mediului, generarea automată de surse, compilarea codului, compilarea testelor, rularea testelor, împachetarea și deploymentul. Există cicluri de viața simplificate pentru curățarea directorului proiectului și pentru construirea documentației publicabile online a proiectului. La execuția procesului de build, utilizatorul trebuie să specifice comenzii mvn o înșiruire de cel puțin un element, elemente care pot fi faze ale ciclului de viață până la care să se meargă (de exemplu, dacă se dorește doar împachetarea, nu și deploymentul; sau doar compilarea, nu și împachetarea); fie goaluri ale unor pluginuri, care vor duce fiecare la efectuarea doar a operațiunilor definite în acele goaluri, în exteriorul unui ciclu de viață.

Funcționalitatea buildului se obține atribuind goaluri din pluginuri diferitelor faze ale ciclului de viață. După cum se arăta mai sus, pentru a obține o împachetare elementară, utilizatorul nu trebuie însă să declare nimic. Aceasta se întâmplă deoarece, în mod implicit, unele faze au câte un goal asociat, utilizatorul asociind alte goaluri doar dacă are nevoie de execuția unor pași suplimentari sau diferiți sau doar altfel configurați. De exemplu, în mod implicit, fazei compile i se asociază goalul compile al pluginului compile; iar faza test are asociat goalul test al pluginului surefire. Într-o fază a ciclului de viață se pot invoca mai multe goaluri din unul sau mai multe pluginuri, dacă se dorește execuția mai multor operațiuni în aceeași fază; dar aceste operațiuni trebuie să fie independente, deoarece utilizatorului nu i se garantează o ordine de execuție a lor; ordinea este în general dată de ordinea declarației goalurilor, dar există variații subtile de la o versiune la alta, mai ales în condițiile în care se invocă în aceeași fază goaluri diferite ale aceluiași plugin. Un control mai strict asupra ordinii operațiunilor poate fi disponibil celor care utilizează pluginul ant, prin care se poate rula o secvență de task ant (de exemplu, mutări și redenumiri de fișiere) ca parte a unui unic goal. Aceasta marchează distanțarea proiectului Maven față de Ant, prin aceea că Maven se adresează celor care doresc simplitate și modularitate, renunțând la controlul excesiv asupra tuturor amănuntelor procesului de build.

Deși lasă impresia utilizatorului că este obligat să lucreze constrâns într-un cadru strict, constrângerile impuse de ciclul de viață favorizează construcția modulară, prin aceea că dacă sunt prea multe operațiuni într-o fază, și care produc fișiere multiple, atunci utilizatorul se poate gândi să despartă modulul în mai multe module care depind unul de altul.

Legături externe

modificare