#07 — Maven i tajemnice pliku pom.xml

By 25 September 2014 February 28th, 2016 Kurs Javy

W opisie narzędzi i przy­go­towa­niu pro­jek­tu wspom­i­nałem o tym, żeby utworzyć pro­jekt Maven. W tej lekcji wyjaśn­imy czym dokład­nie jest maven, do czego jeszcze może­my go wykorzystać.
Maven to w uproszcze­niu narzędzie do zarządza­nia pro­jek­tem, jego zaleznoś­ci­a­mi (czyli np. bib­lioteka­mi które będziemy uży­wać) i struk­turą (np. podzi­ał na mod­uły). Ale to tylko mały wycinek tego, co daje nam to narzędzie. Zachę­cam do zapoz­na­nia się z odnośnika­mi zna­j­du­ją­cy­mi się na dole tej lekcji, które rzucą więcej światła na możli­woś­ci jakie ofer­u­je Maven. Oczy­wiś­cie ist­nieją alter­naty­wne rozwiąza­nia, takie jak np. starszy Ant czy nowszy Gra­dle. Niem­niej Maven dość szy­bko został zaadop­towany przez firmy i nic nie wskazu­je na to, żeby miało się to wkrótce zmienić, dlat­ego z punk­tu widzenia celu tego blo­ga Mave­na należy znać. Po prostu :)

Lekcja

UWAGA! Jeśli instalowałaś inne środowisko niż STS, możesz nie mieć zain­stalowanego Mave­na. Sprawdź w odnośnikach jak to zro­bić i upewnij się, że przed kon­tyn­uowaniem Maven jest zain­stalowany na Twoim komputerze.Maven jest bard­zo rozbu­dowanym narzędziem, jed­nocześnie bard­zo prostym w pod­sta­wowym uży­ciu i użytecznym nawet w małych pro­jek­tach. Cała potę­ga kry­je się w jego budowie — wszys­tkie ele­men­ty, kro­ki i pro­ce­su są dynam­iczne i kon­fig­urowalne, dzię­ki czemu może­my sami wpły­wać na ich dzi­ałanie, włączać/wyłaczać poszczególne ele­men­ty wg potrze­by i dopa­sowywać do swoich potrzeb. Jed­noczes­nie cała kon­fig­u­rac­ja jest w jed­nym miejs­cu wewnątrz pro­jek­tu, co bard­zo poma­ga jeśli prace przy pro­jek­cie odby­wa­ją się na kilku róznych kom­put­er­ach (np. w zes­pole, lub pracu­je­my w domu i w biurze).Miej na uwadze, że przed­staw­ione poniżej infor­ma­c­je to tylko wycinek, który będzie nam potrzeb­ny do dal­szej pra­cy. Gorą­co zachę­cam do zapoz­na­nia się z inny­mi mozli­woś­ci­a­mi tego narzędzia.

Słowniczek

Zaczniemy od wyjaśnienia kilku pojęć. Będą one uży­wane w tej i kole­jnych lekc­jach i kluc­zowe jest, żeby je zrozu­mi­ała. W razie wąt­pli­woś­ci moż­na też poszukać w internecie ich znaczenia — wiele porad­ników i tuto­ri­ali także opisu­je znacze­nie poszczegól­nych słów i określeń.

  • arte­fakt — samoist­na jed­nos­t­ka w pro­jek­cie, arte­fak­tem jest np. każdy z mod­ułów czy każ­da z zależnoś­ci pro­jek­tu. Moż­na powiedzieć, że arte­fakt to takie zbior­cze określe­nie które obe­j­mu­je zarówno pro­jek­ty, mod­uły, bib­liote­ki, plug­iny (czyli ele­men­ty całego pro­ce­su), arche­typy (coś w rodza­ju \‘szablonu\’ pro­jek­tu, który możesz szy­bko skon­fig­urować i uru­chomić) itd.
  • pom.xml — główny plik z ustaw­ieni­a­mi Maven w projekcie
  • repozy­to­ri­um — zbiór arte­fak­tów. Każ­da insta­lac­ja Maven powodu­je utworze­nie lokalnego repozy­to­ri­um, jest także repozy­to­ri­um cen­tralne oraz moż­na korzys­tać z dowol­nych innych repozy­toriów (np. jakiegoś projektu)

Struktura projektu

Korzys­ta­jąc z Mave­na pro­jekt ma stan­dar­d­ową struk­turę (na dysku), w której może­my wyróżnić kil­ka ele­men­tów (w głównym kat­a­logu projektu):

  • pom.xml — główny plik kon­fig­u­racji Maven, omówimy go bardziej szczegółowo poniżej
  • /src/main — kat­a­log, gdzie zna­jdziemy pli­ki naszego pro­gra­mu, są tam dwa podkatalogi: 
    • java — tutaj trafi­a­ją wszys­tkie klasy (cały kod naszego modułu)
    • resources — tutaj będą wszys­tkie pli­ki, które nie są kodem, np. grafi­ki, pli­ki XML, kon­fig­u­rac­je itp (nauczymy się z nich korzys­tać w kole­jnych eta­pach kursu)
    • w przy­pad­ku pro­jek­tów webowych będziemy mieli także kat­a­log webapp, który jest uży­wany do umieszcza­nia wszys­t­kich treś­ci webowych
  • /src/test — ma podob­ną struk­turę jak kat­a­log /main z tą różnicą, że jest on wyko­rzysty­wany tylko w trak­cie automaty­cznych testów. O automaty­cznych tes­tach powiemy sobie więcej w 8 lekcji
  • /target — tutaj trafia skom­pi­lowany pro­jekt (czyli np. w postaci wykony­wal­nego pliku JAR lub aplikacji webowej WAR)

Poza powyższy­mi w naszym mod­ule oczy­wiś­cie mogą się znaleźć dodatkowe pli­ki i kat­a­lo­gi, nie są one jed­nak ściśle związane z samym Maven­em (najczęś­ciej).

Projekty i moduły w Mavenie

Tworząc nowy pro­jekt w mave­nie może­my wybrać jego ‘pack­ag­ing’, czyli sposób, w jaki wszys­tkie ele­men­ty zostaną ostate­cznie połac­zone razem. Ist­nieje kil­ka pod­sta­wowych (oczy­wiś­cie mod­uły i plug­iny mogą rozsz­erzać tą listę):

  • pom
  • jar (domyśl­ny)
  • war (aplikac­je webowe, o tym poroz­maw­iamy w przyszłości)

Pack­ag­ing JAR powodu­je, że w momen­cie uru­chomienia budowa­nia maven wszys­tkie nasze klasy zostaną połąc­zone w jeden plik JAR (który moż­na następ­nie uruchami­ać samodzielnie).
O plikach WAR powiemy sobie w kole­jnych lekc­jach, ale zatrzy­ma­jmy się na moment przy wartoś­ci POM.

Pack­ag­ing POM oznacza mniej więcej tyle, że jest to pro­jekt, który może posi­adać kil­ka mod­ułów (to nie jest wyma­gane, ale na ten moment załóżmy że to najczęst­szy przy­padek, w którym uży­wamy tego ustaw­ienia). Dla przykładu, w dowol­nej dużej aplikacji najczęś­ciej zna­jdziemy wiele pod-pro­jek­tów (mod­ułów, kom­po­nen­tów), z których każdy jest podzielony na kil­ka ele­men­tów (np. osob­no jest kod związany z bazą danych, z logiką biz­ne­sową oraz z wyświ­et­laniem — warst­wą prezen­tacji). Z punk­tu widzenia maven jeden taki kom­po­nent (pod-pro­jekt) to pro­jekt (lub mod­uł) który ma pack­ag­ing = POM, z kolei każdy z ele­men­tów (logi­ka biz­ne­sowa, obsłu­ga bazy danych itp) to osob­ne mod­uły, które mają pack­ag­ing JAR lub WAR i w sekcji par­ent ustaw­iony ten pro­jekt, który ma pack­ag­ing ‘POM’.

W eclipse może­my ustaw­ić taki pro­jekt na dwa sposo­by — albo tworząc nowy mod­uł i poda­jąc odpowied­nie dane w sekcji ‘par­ent’, albo otwier­a­jąc plik pom.xml nadrzęd­nego mod­ułu i w sekcji ‘mod­ules’ wybier­a­jąc opcję ‘cre­ate’ (opc­ja ‘add’ pozwala nam wybrać już ist­nieją­cy mod­uł, którym chce­my zarządzać w ten sposób) i uzu­peł­ni­a­jąc dane jak przy nor­mal­nym tworze­niu mod­ułu Mavenowego.

Taka kon­fig­u­rac­ja jest bard­zo wygod­na, ponieważ wszys­tkie ustaw­ienia ‘nadrzęd­nego’ POMa są też dostęp­ne w POMie podrzęd­nym, może­my więc z jed­nego miejs­ca zarządzać wer­s­ja­mi bib­liotek, których uży­wamy, uży­wać ustaw­ień i kon­fig­urować plug­iny. Więcej o innych zas­tosowa­ni­ach będziemy mówili w kole­jnych lekc­jach, póki co będzie to dla nas przy­datne także po to, aby uporząd­kować nasz kod i podzielić go na moduły.

pom.xml

Plik pom.xml jest tym, co łączy pro­jekt w Javie oraz Maven’a ;) To w nim jest cała kon­fig­u­rac­ja związana z pro­jek­tem, opis jak ma być budowany, kon­fig­u­rac­ja plug­inów itp. Nie będziemy tutaj opisy­wać całej struk­tu­ry pliku pom, ponieważ wyz­nacza to znacznie poza ramy tego kur­su, a jedynie nakreślimy najważniejsze elementy.To, co musi zaw­ier­ać plik pom.xml, to koor­dy­naty arte­fak­tu, czyli groupId oraz arti­fac­tId. Jeśli pro­jekt nie ma rodz­i­ca (tag <par­ent>), musimy określić także numer wer­sji. Iden­ty­fika­tor grupy to najczęś­ciej nazwa pro­jek­tu, pod­czas gdy iden­ty­fika­tor arte­fak­tu to unikalna nazwa np. mod­ułu — idea jest taka, że poszczególne mod­uły tego samego pro­jek­tu mają wspól­ny groupId, ale unikalny arti­fac­tId. Para wartoś­ci groupId i arti­fac­tId powin­na być unikalna.

Plik ten pozwala nam także określić, z jakich bib­liotek i innych mod­ułów korzys­ta nasz mod­uł. Służy do tego tag <depen­den­cies>, który może wys­tąpić tylko raz — wewnątrz tego tagu może­my dodać wiele tagów <depen­den­cy>. Tag depen­den­cy może wskazy­wać na dowol­ny arte­fakt z repozy­to­ri­um cen­tral­nego, lokalnego lub dowol­nego innego skon­fig­urowanego w ustaw­ieni­ach Maven. Musi on zaw­ier­ać trzy infor­ma­c­je — groupId, arti­fac­tId (razem to tzw. coor­di­nates — czyli pre­cyzyjne określe­nie, o który arte­fakt nam chodzi) oraz ver­sion — wer­sję  (to nie do koń­ca praw­da, w więk­szych pro­jek­tach sto­su­je się tzw. depen­den­cy­Man­age­ment, czyli cen­tralne zarządzanie numera­mi wer­sji pozwala­jące pom­inąć numer wer­sji w tagu depen­den­cy; zain­tere­sowanych odsyłam do doku­men­tacji Mave­na, nie ma w tym żad­nej magii i w prostych pro­jek­tach jest to mało przy­datne). Przykład­owy plik pom.xml wyglą­da następujaco:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <version>1</version>
</project>

Jest to tzw. min­i­mal­ny plik pom.xml — posi­a­da tylko wyma­gane informacje.

<project>
  ...
  <properties>
    <mavenVersion>2.1</mavenVersion>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-artifact</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-project</artifactId>
      <version>${mavenVersion}</version>
    </dependency>
  </dependencies>
  ...
</project>

Więcej przykładów zna­jdziesz na stron­ie Mave­na, pod adresem http://maven.apache.org/guides/introduction/introduction-to-the-pom.html

Cykl życia (domyślny)

Cała idea dzi­ała­nia Mave­na jest zbu­dowana wokół tzw. cyk­lu życia (maven build life­cy­cle). Każdy z kroków to kole­jny ele­ment na drodze od kodów źródłowych do pro­jek­tu uru­chomionego na ser­w­erze (tak, Maven może także to zro­bić). Poniższy dia­gram przed­staw­ia (uproszc­zony) domyśl­ny cykl życia projektu.

Domyślny (uproszczony) cykl życia projektu

Domyśl­ny (uproszc­zony) cykl życia projektu

Krótkie omówie­nie poszczegól­nych faz:

  • val­i­date — wal­i­dac­ja, na tym etapie sprawdzane jest, czy kod źródłowy jest poprawny, czy wszys­tkie pli­ki zaw­ier­a­ją praw­idłowe ele­men­ty (o ile Maven ma infor­ma­c­je, jak to sprawdz­ić) itp., ogól­nie jest to sprawdze­nie, czy pro­jekt moż­na skompilować
  • com­pile — kom­pi­lac­ja pro­jek­tu, czyli zami­ana kodów źródłowych na kod zrozu­mi­ały dla maszyny wirtualnej
  • test — automaty­czne wyko­nanie testów, o których to będzie kole­j­na lekcja
  • pack­age — łącze­nie ele­men­tów stwor­zonych w poprzed­nich eta­pach w tzw. deliv­er­able, czyli np. plik JAR który moż­na uru­chomić lub plik WAR który moż­na uru­chomić na serwerze
  • inte­gra­tion-test — to kole­j­na seria automaty­cznych testów, tym razem inte­gra­cyjnych. Testy inte­gra­cyjne to w skró­cie testy sprawdza­jące czy nasz kom­po­nent współpracu­je z inny­mi w ramach więk­szego sys­te­mu. Testy tego rodza­ju nie będą omaw­iane w tym kur­sie (ale może w przyszłoś­ci pojawi się o nich parę słów na blogu w ramach luźnej notatki :) )
  • ver­i­fy — wery­fikac­ja, czy stwor­zona pacz­ka speł­nia kry­te­ria jakoś­ciowe (o kry­te­ri­ach, metrykach itp. powiemy sobie w przyszłości)
  • install — insta­lac­ja pacz­ki wygen­erowanej w kroku pack­age. Przy czym uwa­ga, insta­lac­ja oznacza tyle, że arte­fakt (czyli wynik dzi­ała­nia pack­age) zostanie umieszc­zony w repozy­to­ri­um Mave­na (domyśl­nie lokalnym, ale może­my też umieś­cić je w repozy­to­ri­um zdal­nym) i będzie dostęp­ny dla innych mod­ułów (np. jako zależność)
  • deploy — umieszcze­nie arte­fak­tu np. na ser­w­erze za pomocą FTP czy jakiegoś API ser­w­era aplikacji

Maven’a uruchami­amy prze­chodząc do kat­a­logu z plikiem pom.xml i wpisu­jac mvn <step> . Możli­woś­ci jest oczy­wiś­cie więcej, może­my wykon­ać konkret­ny cel (‘pod­krok’ w ramach danego kroku) ale ponieważ w tym kur­sie Maven posłuży nam tylko jako narzędzie dodatkowe, nie będziemy omaw­iać szczegółów. Zain­tere­sowanych odsyłam do doku­men­tacji lub książek na tem­at samego Mavena :)

To, co trze­ba wiedzieć, to to, że wywołaniem konkret­nego kroku (np. poprzez mvn install) wykonu­je­my wszys­tkie kro­ki po kolei, aż do tego, który określil­iśmy (w tym przy­pad­ku wszys­tkie kro­ki poza ostat­nim — deploy). Najczęst­szym sposobem uży­cia (i ten proszę sobie napisać na karteczce i nakleić na mon­i­tor) to polece­nie mvn clean install — cel clean nie należy do głównego cyk­lu życia (ale może­my go wykon­ać tak jak dowol­ny inny krok, po pros­tu wstaw­ia­jąc go po spacji do polece­nia). To polece­nie najpierw usunie wszys­tkie stare pli­ki (to ważne, ponieważ cza­sem nieusunię­cie plików może prowadz­ić do błędów, które trud­no zlokali­zować) a następ­nie skom­pilu­je pro­jekt, zapaczku­je go (stworzy arte­fakt) i umieś­ci go w repozy­to­ri­um (domyśl­nie lokalnym). Arte­fakt zna­jdziemy też oczy­wiś­cie w kat­a­logu /target jako plik .jar / .war .

Zadanie

Jeśli pro­jekt, nad którym pracu­jesz, nie jest jeszcze pro­jek­tem typu maven (moż­na to poz­nać np. po tym, że nie ma w jego głównym kat­a­logu pliku pom.xml), skon­wer­tuj go na pro­jekt Maven (klika­jąc prawym przy­ciskiem mysz­ki na pro­jekt w Eclipse, a następ­nie wybier­a­jąc odpowied­nią opcję konwersji).Zmodyfikuj plik pom.xml tak, aby zaw­ier­ał poniższe zmiany:

  • Uzu­pełnij nazwę pro­jek­tu i jego opis oraz adres URL (jeśli nie posi­adasz włas­nej strony, jako adres URL podaj stronę tego projektu)
  • Skon­fig­u­ruj pro­jekt tak, aby plik JAR moż­na było uru­chomić bezpośred­nio, klika­jąc na niego dwukrot­nie myszką (tzw. self-exe­cutable JAR). Zrób to wyłącznie poprzez mody­fikac­je w pliku pom.xml
  • Dodaj zależność do arte­fak­tu org.springframework:spring-core w najnowszej wer­sji (wyszukaj wer­sję w repozy­to­ri­um centralnym)

Następ­nie dodaj moduły:

  • koty-domain i prze­nieś do niego klasę Kot
  • koty-appli­ca­tion i umieść w nim resztę klas. Do tego mod­ułu prze­nieś zależność do spring-core

Pamię­taj, że część zmi­an z pier­wszej częś­ci zada­nia będziesz musi­ał prze­nieść do mod­ułu (chodzi głównie o kon­fig­u­rację exe­cutable JAR — do mod­ułu koty-application)

Upewnij się, że nadal moż­na skom­pi­lować pro­jekt (dodaj zależnoś­ci jeśli jest taka potrzeba).

Podpowiedzi

More »
  1. Real­izuj jed­ną zmi­anę na raz, przy pier­wszym spotka­niu Maven może wydać Ci się ogrom­nym i skom­p­likowanym narzędziem, ale tak naprawdę znacznie ułatwia życie pro­gramisty :) Ważne jest, żeby się do niego nie zraz­ić, ale jed­nocześnie poz­nać ograniczenia i wymogi
  2. Zawartość repozy­to­ri­um cen­tral­nego możesz łat­wo przeszuki­wać na stron­ie mvnrepository.com
  3. Jeśli po prze­niesie­niu klasy pojaw­ią się błędy, pozwól środowisku IDE rozwiązać je za Ciebie (Ctrl+1 w środowisku Eclipse). Nastep­nie prześledź zmi­any w plikach pom.xml

zip Pobierz rozwiązanie tego zadania

Licencja Creative Commons

Jeśli uważasz powyższą lekcję za przy­dat­ną, mamy małą prośbę: pol­ub nasz fan­page. Dzię­ki temu będziesz zawsze na bieżą­co z nowy­mi treś­ci­a­mi na blogu ( i oczy­wiś­cie, z nowy­mi częś­ci­a­mi kur­su Javy). Dzięki!