Siła Projektu Apache Maven

Wraz z rozrostem projektów informatycznych proces budowania danej aplikacji staje się bardziej skomplikowany. Zbudowanie jednego projektu może być uzależnione od realizacji innego. Podczas tego wersje bibliotek z czasem się zmieniają na wyższe lub dochodzą nowe.

Weźmy pod uwagę, że w takiej sytuacji programista nie będzie pobierał ręcznie nowej wersji biblioteki i zastępował starszą. Powstało więc narzędzie, które będzie te wszystkie czynności (i wiele więcej) robiło za nas. Mało tego, ma ono pamiętać jaki projekt od którego zależy, w przypadku zmian wersji bibliotek – sam ma to zauważyć i sam ściągnąć je z Internetu, ma sam odpalić testy i pilnować aby przechodziły a na koniec tak zbudowaną aplikację wrzucić na serwer produkcyjny i odpalić.

Podczas pierwszego spotkania z Mavenem – jego układ może się wydawać nieco skomplikowany,  jednak tak jak podczas nauki programowania ważne jest aby nie łapać za wiele sznurków jednocześnie – poznanie podstaw Mavena, do czego służą każde z jego sekcji pomoże w późniejszym zrozumieniu nawet złożonych projektów.

W poprzednim artykule przeszliśmy proces stworzenia pierwszej aplikacji zarządzanej przez Mavena. Teraz omówimy poszczególne elementy zaczynając od drzewa

Gdy korzystamy z IntelliJ IDEA to mamy wbudowaną wersję Mavena, która nam w zupełności wystarczy. Jeśli korzystalibyśmy z innego IDE np Eclipse, musielibyśmy dodać plik mvn do PATH systemu.

|- src 
|    \
|     |- main 
|     |     \
|     |     |- java
|     |     |- resources
|     |- test
|           \
|           | - java
|           | - resources
|- target
|- pom.xml
src/main/java tutaj piszemy nasz kod Java projektu (pogrupowane klasy w package)
src/main/resources pliki konfiguracyjne dla klas Java, np. dla różnych bibliotek itp.
src/test/java kod Java dla testów aplikacji
src/test/resources pliki konfiguracyjne dla klas testowych
target folder gdzie Maven realizuje swoje pliki
pom.xml główny plik konfiguracyjny projektu

Przyjmijmy, że posiadamy już jakiś kod dzięki utworzonemu projektowi (artykuł wcześniej). Chcielibyśmy teraz nim zarządzać. Aby to jednak zrobić musimy być świadomi jak pracuje Maven. Zamysł jego działania opiera się o tzw. cykle życia (build lifecycle). Cykle życia składają się z faz, które są kolejnymi elementami na drodze od kodu źródłowego do projektu uruchomionego np. na serwerze.

Po prawej stronie w naszym IDE będziemy mieć zakładkę Maven Projects. Znajdziemy tam drzewa, gdzie najwyższy poziom będzie nazywał się jak nasza aplikacja, czyli hello, zaś pod nim będzie gałąź Lifecycle oraz Plugins. Z listy cykli życia (Lifecycle) klikamy dwa razy lewym przyciskiem myszy na opcji clean a następnie analogicznie na opcji install. Jak zobaczymy – dużo będzie działo się w konsoli. Maven po kolei będzie wykonywał to co mu powiedzieliśmy. Z reguły pierwsze uruchomienie powoduje, że budowanie trwa dłużej gdyż Maven musi sobie pościągać niezbędne biblioteki. Skutek pracy pojawi się w katalogu target.

Istnieją 3 podstawowe cykle życia:

  • clean – czyści po sobie poprzednie efekty budowania aplikacji (często oznacza to wyczyszczenie folderu target)
  • site – buduje dokumentację projektu (np. tzw. javadoc)
  • domyślny cykl, który z kolei składa się z następujących faz (w prawidłowej kolejności):
validate validuje strukture projektu
compile kompiluje kod źródłowy
test uruchamia testy
package tworzy artifact w katalogu określonym jako ‚target’
integration-test deploy artifaktu w środowisku integracyjnym
integration-test uruchamia walidacje paczki
install instaluje paczke w lokalnym repozytorium
deploy kopiuje artifact na serwer

Po wykonaniu poprzedniej procedury otrzymamy widoczny poniżej wynik w konsoli. Jeśli przyjrzymy się w logi fazy (install) zauważymy, że na końcu były logi w stylu:

Maven działa na zasadzie trzymania wybudowanych projektów w repozytoriach (wytworzonych w fazie install). Po co zbudowaną aplikację wrzuca od razu do repozytorium utworzonym w jednym z katalogów naszego komputera? Odpowiedź jest prosta: gdybyśmy chcieli za chwilę użyć jej w innym projekcie – Maven znajdzie ją sobie w repozytorium. Tak z resztą się często dzieje – gdy nasza aplikacja składa się z kilku podprojektów (tzw. modułów) – to Maven buduje najpierw te, które nie zależą od innych projektów, następnie wrzuca je do repozytorium a potem przechodzi do kolejnych projektów – a gdy któryś kolejny projekt potrzebuje kodu projektu już zbudowanego wcześniej – Maven po prostu sięga po jego kod do repo.

Plik pom.xml – czyli sercem naszej aplikacji

Przyjrzyjmy się temu plikowi. W lewej stronie naszego IDE (drzewa) odnajdźmy plik pom.xml otwierając go

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>pl.amesoft.hello</groupId>
  <artifactId>hello</artifactId>
  <version>1.0-SNAPSHOT</version>
</project>

Pierwsza część jest konwencją która jest stała

<project xmlns="http://maven.apache...

i nie powinna nas interesować  Natomiast powinniśmy się zainteresować tym co jest dalej:

groupId twórca (pl.amesoft.hello)
artifactId nazwa aplikacji (hello)
packaging sposób pakowania aplikacji (jar, war, ear, pom). My znamy tylko jar
version wersja naszej aplikacji
name nazwa wyświetlana (opcjonalnie)
url link do strony projektu (opcjonalnie)
dependencies zależności od innych modułów (opcjonalnie)

Zależności – co to takiego ?

Postaram się ująć to w najprostszy sposób. Jest to projekt(biblioteka) od którego zależy nasz obecnie pisany projekt. Jeżeli rozbudowujemy teraz aplikację internetową to zależeć ona będzie np. od projektu(biblioteki), który potrafi zapisywać dane do bazy danych. Będziemy musieli dołączyć więc zależność do projektu zarządzania bazą danych. Maven zaś pobierze potrzebne kody do naszego projektu tak abyśmy mogli używać obiektów z tamtego projektu. Każda biblioteka z której korzystamy jest zależnością.

<dependencies>
  <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.11</version>
    <scope>test</scope>
  </dependency>

  <dependency> 
   kolejna zależność...
  </dependency>

 <dependency> 
  kolejna zależność...
 </dependency>
</dependencies>

IntelliJ powinno w tle wykryć, że zmienił się POM i spróbować zaciągnąć zależności przy pomocy Mavena. Jeśli nie, należy jak poprzednio uruchomić opcję clean oraz install.

Podczas budowania aplikacji (Maven install) zauważymy, jak nasza biblioteka jest ściągana z Internetu… a następnie wrzucana do naszego repozytorium (~/.m2/repository/…). Jeśli za chwilę drugi raz będziemy budować – Maven tylko sprawdzi czy nic się nie zmieniło z tą wersją biblioteki odczytując sumę kontrolną – a następnie stwierdzi, że ma już tą bibliotekę zaciągniętą wcześniej – i użyje jej.

Pluginy

Mają za zadanie rozszerzyć funkcjonalności Mavena. Mamy możliwość wskazania z jakiej wersji Javy chcemy korzystać, mamy możliwość wykorzystania pluginów, które same połączą się ze zdalnym serwerem i podmienią nam wersje aplikacji na tą najświeższą po czym wykona restart maszyny i wiele więcej…

<plugins>
  <plugin>
    <artifactId>maven-clean-plugin</artifactId>
    <version>3.1.0</version>
  </plugin>

  <plugin>
    kolejny plugin...
  </plugin>

</plugins>

Oprócz oczywistych oszczędności czasu można wyróżnić szereg innych zalet jakie daje Automatyzacja procesu budowania aplikacji przez Mavena:

  • automatyczna kompilacja kodu
  • usunięcie starych plików z poprzedniego budowania aplikacji
  • pilnowanie kolejności budowania modułów aplikacji (pilnowanie zależności projektu od projektu)
  • pilnowanie bibliotek oraz ich wersji
  • wykonywanie testów aplikacji
  • generowanie pliku .jar (.war) z naszą aplikacją
  • generowanie dokumentacji
  • uniwersalność środowiska/konfiguracji – działa u mnie? powinno działać u Ciebie!
    i wiele innych

Poza prostym budowaniem projektu i ściąganiem niezbędnych bibliotek, Maven potrafi znacznie więcej. Warto poznać takie zagadnienia jak choćby:

  • Używanie parametrów w projektach
  • Tworzenie tzw. Parent POM’a, który daje możliwość zarządzać wieloma projektami, które „dziedziczą” właściwości po tym POMie. Można w jednym miejscu np. zmienić wersję biblioteki na nowszą – i wszystkie projekty będą miały ją zaktualizowaną bez potrzeby szukania jej po wszystkich POM innych projektów
  • Używanie pliku settings.xml, który pozwala ustawić konfigurację dla wszystkich projektów – np. listę repozytoriów Mavena, hasła do GIT, jakieś wartości parametrów itp,
  • Używanie profili Mavena
  • i wiele innych
W pilnych sprawach zachęcamy do kontaktu telefonicznego