Kontynuując myśl z poprzedniego artykułu wyjaśnijmy sobie jakie są cykle życia projektu w ujęciu Mavena. Ta idea jest najistotniejsza w całym narzędziu, ponieważ definiuje proces budowania oraz dystrybucji tworzonych aplikacji. Nie przedłużając przejdźmy do przedstawienia tych cykli i sprawdźmy co się na nie składa.

Wbudowane cykle życia

W celu wdrożenia i dystrybucji docelowego projektu Maven musi go zbudować w oparciu o określony cykl życia, inaczej mówiąc lifecycle. Domyślnie dostępne są 3 takie cykle:

  • default - główny lifecycle, którego odpowiedzialnością jest wdrożenie projektu
  • clean - czyści projekt oraz usuwa wszystkie wygenerowane pliki z poprzedniego budowania
  • site - tworzy dokumentację projektu w formie strony

Na każdy z cykli składa się kilka phases. Dla clean są to 3 phases, dla site - 4 phases, natomiast dla default aż 23 phases. Przechodząc dalej, czym są dokładnie te “fazy”?

Czym są phases Mavena?

Phase w Mavenie to inaczej krok, element składowy wybranego cyklu życia budowania projektu, który odpowiedzialny jest za wykonanie danego zadania. Przyjrzyjmy się, więc osiemu najważniejszym phases dla wcześniej poznanego default:

  • validate - weryfikuje czy wszystkie niezbędne informacje do zbudowania projektu są dostępne
  • compile - kompiluje kod źródłowy
  • test - uruchamia wszystkie testy jednostkowe
  • package - pakuje skompilowany kod do formatu dystrybucji jakim jest np. jar albo war
  • verify - sprawdza czy spakowany projekt spełnia podane kryteria jakości np. checkstyle
  • install - instaluje paczkę na lokalnym repozytorium
  • deploy - kopiuje paczkę do zewnętrznego repozytorium

Resztę możemy znaleźć na stronie Mavena. Żeby uruchomić dany phase w wierszu poleceń musimy podać następująca komendę mvn <PHASE>. Tylko jest tutaj istotna jedna bardzo ważna rzecz: uruchomiony zostanie nie tylko wybrany phase, ale również wszystkie go poprzedzające. Jest to bardzo logiczne, ponieważ, aby przetestować projekt trzeba go najpierw skompilować. Dla przykładu jeśli napiszemy mvn deploy, co jest ostatnim phase w cyklu default, to wykonają się wszystkie 22 poprzedzające go kroki wraz z nim.

Wywołanie poprzedzających phases przy użyciu wybranego phase
Wywołanie poprzedzających phases przy użyciu wybranego phase

Nie każdy phase powinien być wywołany z wiersza poleceń

Istnieją takie phases, które raczej nie powinny znaleźć się w roli komendy w konsoli. Łatwo je rozpoznać, ponieważ zaczynają się od prefiksu pre-*, post-* czy process-*. Są to raczej części składowe jakiegoś procesu, które wytwarzają pośrednie rezultaty kompletnie nieprzydatne poza nim. Z drugiej strony jeśli użyjemy phase np. integration-test bez wywołania jego części składowych to możemy otrzymać środowisko znajdujące się w stanie zawieszenia. Wtedy uruchomiony kontener Dockerowy czy serwer Tomcata może pozostać uruchomiony i Maven nie zakończy działania sam z siebie.

No dobrze, możemy pójść jeszcze dalej w rozdrabnianiu tych dostępnych komend. Z dokumentacji Mavena dowiadujemy się, że każdy phase składa się z jeszcze mniejszych części nazywanych goals.

Najmniejsza składowa, czyli goals

Goal jest najmniejszą jednostką z całej tej organizacji narzędzia. Reprezentuje on część pluginu, który został zaprogramowany do wykonania specjalistycznego zadania, którego już nie deleguje dalej. Phase grupuje w sobie goals i wykonuje je sekwencyjnie, w kolejności jakiej zostały zadeklarowane. Przyjrzyjmy się zatem kilku przykładom:

  • compiler:compile - goal compile z pluginu o nazwie compiler (podpięty jest do phase compile)
  • compiler:testCompile - goal testCompile z pluginu o nazwie compiler (podpięty jest do phase test-compile)
  • surefire:test - goal test z pluginu o nazwie surefire (podpięty jest do phase test)
  • install:install - goal install z pluginu o nazwie install (podpięty jest do phase install)
  • jar:jar - goal jar z pluginu o nazwie jar (podpięty jest do phase package)

Wypada dodatkowo doprecyzować, że nazwa pluginu jak np. compiler czy surefire to tylko skrót dla pełnej nazwy - maven-compiler-plugin i maven-surefire-plugin.

Wpisując komendę mvn help:describe -Dcmd=<PHASENAME> do wiersza poleceń, będąc w katalogu projektu z wcześniejszego artykułu, (oczywiście podmieniając PHASENAME na np. compile) otrzymamy poniższy komunikat.

'compile' is a phase corresponding to this plugin:
org.apache.maven.plugins:maven-compiler-plugin:3.1:compile

It is a part of the lifecycle for the POM packaging 'jar'. This lifecycle includes the following phases:
* validate: Not defined
* initialize: Not defined
* generate-sources: Not defined
* process-sources: Not defined
* generate-resources: Not defined
* process-resources: org.apache.maven.plugins:maven-resources-plugin:2.6:resources
* compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:compile
* process-classes: Not defined
* generate-test-sources: Not defined
* process-test-sources: Not defined
* generate-test-resources: Not defined
* process-test-resources: org.apache.maven.plugins:maven-resources-plugin:2.6:testResources
* test-compile: org.apache.maven.plugins:maven-compiler-plugin:3.1:testCompile
* process-test-classes: Not defined
* test: org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test
* prepare-package: Not defined
* package: org.apache.maven.plugins:maven-jar-plugin:2.4:jar
* pre-integration-test: Not defined
* integration-test: Not defined
* post-integration-test: Not defined
* verify: Not defined
* install: org.apache.maven.plugins:maven-install-plugin:2.4:install
* deploy: org.apache.maven.plugins:maven-deploy-plugin:2.7:deploy

Potwierdziliśmy tym samy, że phase compile korzysta z pluginu maven-compiler-plugin, a dokładniej z jego goal o nazwie compile. Przy okazji dostajemy informację o reszcie phases i np. phase deploy korzysta z goal pluginu maven-deploy-plugin deploy. Muszę przyznać, że jest to zagmatwane na pierwszy rzut oka, ponieważ najczęściej wszystkie składowe mają tą samą nazwę i ciężko dojść co jest czym. Jednak mam nadzieję, że ten opis pomógł Ci to lepiej zrozumieć.

Przy okazji dodam, że phase ma zależność do goal 0..*, czyli może mieć zero, jeden albo wiele goals. Jeżeli nie ma żadnej składowej to w ogóle się nie wykona, natomiast jeśli jest już co najmniej jeden goal to taki phase wykona się na 100%.

Poszczególne części składowe komend Mavena
Poszczególne części składowe komend Mavena

Wywołanie goal z konsoli

Możemy bezpośrednio wywołać dany goal nawet jeśli nie jest podpięty pod żaden phase. Dokonujemy tego przez użycie komendy mvn <PLUGIN>:<GOAL>. Każdy plugin ma w sobie goal o nazwie help, więc dzięki wywołaniu go w konsoli przy wykorzystaniu wcześniej pokazanej składni (np. dla pluginu compiler - mvn compiler:help) dowiadujemy się jakie goals są dostępne w danym pluginie.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
--- maven-compiler-plugin:3.8.0:help (default-cli) @ my-app ---
Apache Maven Compiler Plugin 3.8.0
  The Compiler Plugin is used to compile the sources of your project.

This plugin has 3 goals:

compiler:compile
  Compiles application sources

compiler:help
  Display help information on maven-compiler-plugin.
  Call mvn compiler:help -Ddetail=true -Dgoal=<goal-name> to display parameter
  details.

compiler:testCompile
  Compiles application test sources.

Jak widać mamy 3 goals: help, compile oraz testCompile, które poznaliśmy wcześniej.

Sposób sekwencyjnego uruchamiania phases i goals z konsoli

Z wiersza poleceń możemy wywoływać poszczególne phases i goals pojedynczo, czyli np. mvn compile, mvn install, mvn deploy:deploy czy mvn surefire:test. Jednak istnieje również możliwość ich łączenia. Robimy to po prostu podając kolejne polecenia oddzielone spacją.

1
mvn clean dependency:copy-dependencies package

Na początku uruchomiony zostanie phase clean z lifecycle clean (wszystkie phases poprzedzające clean wraz z nim), następny na ogień pójdzie goal copy-dependencies z pluginu dependency i finalnie phase package (poprzedzające phases wraz z package).

Podsumowanie

Mam nadzieję, że nie zagmatwałem całej tej filozofii z uruchamianiem odpowiednich zadań Mavena. Również liczę na to, że teraz już będziesz wiedział/a co się dzieje w tle jeżeli wpiszesz mvn clean install po raz kolejny do konsoli. W następnym artykule chciałbym zagłębić się w strukturę pliku pom.xml, na którego lekturę już teraz serdecznie Cię zapraszam!