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.
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%.
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.
--- 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ą.
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!