%title%
Jedną z ważniejszych zasad w programowaniu jest korzystanie z fragmentów kodu opracowanych już przez kogoś innego. Niektórzy nazywają tą regułę 'nie wymyślaniem koła od nowa’. Chodź z pozoru wydaje się, iż dobry programista powinien wiedzieć wszystko i napisać kod sam od początku do końca, jest to błędne myślenie. We współczesnym programowaniu, bardzo ważna jest znajomość zewnętrznych bibliotek (frameworków) i umiejętne wykorzystanie ich potencjału w swojej aplikacji. Niestety obsługa dziesiątek zewnętrznych zależności nie jest łatwe. Z pomocą przychodzi tutaj narzędzie, służące do zarządzania projektami Java, o nazwie Maven.
- Technologie służące do zarządzania projektami
- Instalacja narzędzia
- Praca z linii komend na Linuksie
- Maven na Windowsie
- Tworzenie projektu dzięki archetypu
- Cykl życia projektu
- Sekcje pliku pom.xml
- Struktura projektu
- Repozytoria
- Konfiguracja
- Podsumowanie
Technologie służące do zarządzania projektami
Najprostszym sposobem budowania projektu w języku Java, jest skorzystanie z kompilatora Javac i wywołanie odpowiedniego polecenia dzięki linii komend. Nie jest to jednak wydajne rozwiązanie, zwłaszcza w przypadku wielkich modułowych aplikacji. Stąd też, podczas rozwoju języka, gwałtownie przyszedł czas na zautomatyzowanie fazy budowania projektu.
Pierwszymi, znanymi mi, sposobami na usprawnienie budowania programów opartych na JDK, było tworzenie tzw. makefile’i, czyli prostych skryptów, które sekwencyjnie wykonują operacje potrzebne do skompilowania kodu. Szczerze mówiąc, tylko raz spotkałem się z takim sposobem zarządzania projektem i nie sądzę, abyś kiedykolwiek musiał z niego korzystać. Powodem zażegnania używania makefile’i było skomplikowana składnia i trudność w tworzenia większych skryptów, opartych na specjalnych sekcjach.
Kolejnym etapem w rozwoju zarządzania projektami Java, była technologia o nazwie Ant. Pisanie skryptów, zastąpiono tu uszeregowaną strukturą xml. Xml to plik, który podobnie jak HTML, opiera się na korzystaniu ze specjalnych tagów, które porządkują czytelność skryptu, a także pozwalają je zagnieżdżać, tworząc strukturę drzewiastą. Ant bardzo ułatwił kompilację kodu, jednak wciąż był za skomplikowany. Ponad to nie posiada wbudowanego wsparcia zarządzania zależnościami, przez co nie ma zastosowania w nowoczesnym programowaniu (Ant nie potrafi w łatwy sposób pobierać zewnętrzne biblioteki, uzupełniające JDK).
Wszystkie powyższe problemy rozwiązywał Maven. Framework ten posiada prostą budowę opartą o xml. Umożliwia w łatwy sposób zarządzanie zależnościami i pluginami, czy obsługiwanie faz budowania projektu.
Instalacja narzędzia
Maven można używać z poziomu linii komend albo z poziomu IDE. Tak naprawdę oba sposoby nie wykluczają się wzajemnie, co więcej można powiedzieć, iż się uzupełniają. Różnica jest taka, iż w przypadku korzystania z IDE nie musisz nic ustawiać, ponieważ mają one przeważnie skonfigurowaną „wtyczkę” do Mavena. Dlatego też w tym wpisie skupię się na pracy z linii komend, która jest bardziej wymagająca.
Praca z linii komend na Linuksie
Instalacja Mavena, korzystając z powłoki systemu Linuks, jest bardzo łatwa. Wystarczy odpalić w terminalu polecenie:
sudo apt install mavenJeśli nie wiesz, czy Maven nie został już zainstalowany, wystarczy, iż wpiszesz po prostu mvn –version. A w terminalu powinna wyświetlić się prośba o zainstalowanie narzędzia. Maven wymaga instalacji JDK, więc jeżeli jeszcze go nie posiadasz na swoim systemie, to bezwzględnie musisz to zrobić.
Apache Maven 3.6.3 Maven home: /usr/share/maven Java version: 11.0.15, vendor: Private Build, runtime: /usr/lib/jvm/java-11-openjdk-amd64 Default locale: en, platform encoding: UTF-8 OS name: "linux", version: "5.10.16.3-microsoft-standard-wsl2", arch: "amd64", family: "unix"Maven na Windowsie
Tutaj sytuacja jest bardziej skomplikowana. W przypadku tej opcji należy ściągnąć fizyczną paczkę ze strony https://maven.apache.org/download.cgi, rozpakować w dowolnym katalogu a następnie ustawić zmienne środowiskowe w systemie (konkretnie zmienną MAVEN_HOME oraz PATH). W ten sposób konsola Windows zacznie 'dostrzegać’ narzędzie. W nowo stworzonej MAVEN_HOME powinien widnieć ścieżka, gdzie ściągnięty plik został rozpakowany (np. C:\Users\Mariusz\Development\maven\apache-maven-3.5.3). Natomiast do zmiennej PATH (powinna już istnieć) należy dodać wartość %MAVEN_HOME%\bin.
Tworzenie projektu dzięki archetypu
Aby stworzyć nowy projekt wystarczy odpalić komendę mvn archetype:generate. Pozwoli ona stworzyć plik konfiguracyjny pom.xml, który zawiera wszelkie informacje dla frameworka, w jaki sposób budować projekt. Struktura samego pliku jest definiowana przez tzw. archetyp, który domyślnie ma poustawiane pewne funkcjonalności (np. pluginy, czy zależności). Najprostszym archetypem jest maven-archetype-quickstart, który tworzy najprostszy z możliwych szkieletów projektu. Żeby zacząć pracę, używając tego schematu, należy jedynie zdefiniować grupę i artefakt.
mvn archetype:generate -DgroupId=pl.developeronthego -DartifactId=maven-test -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=falseJeśli wszystko zostało zdefiniowane prawidłowo, to w katalogu, gdzie została wywołana ta komenda, powinien powstać nowy katalog z nazwą artefaktu (w moim przypadku: maven-test), a w nim wyżej wspomniany plik pom.xml.
Zawartość pliku pom.xml wygląda tak:
<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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>pl.developeronthego</groupId> <artifactId>maven-test</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>maven-test</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>Aby się upewnić, iż projekt będzie zbudowany z adekwatną wersją JDK, warto też dodać sekcję properties:
<properties> <maven.compiler.target>1.8</maven.compiler.target> <maven.compiler.source>1.8</maven.compiler.source> </properties>Cykl życia projektu
Po stworzeniu projektu, framework pozwala wywoływać konkretną fazę jego budowania. Jest to bardzo wygodne rozwiązanie, ponieważ czasami nie chcesz przebudowywać całej aplikacji. Wystarczy Ci np. odpalenie samych testów jednostkowych (w celu sprawdzenia ich poprawności). Do tego służą właśnie fazy budowania.
validate – waliduje projekt, czy jest poprawny oraz czy wszystkie niezbędne informacje są dostępne
compile – wykonuje kompilację kodu w projekcie
test – odpala testy jednostkowe (np. dzięki junit)
package – produkuje plik *jar po skompilowaniu kodu
verify – odpala testy integracyjne (np. służąc do sprawdzenia połączenia z bazą danych)
install – podstawowa komenda, buduje cały projekt i zapisuje rezultat w lokalnym repozytorium (patrz niżej)
deploy – w zależności od konfiguracji, umożliwia załadowanie gotowego projektu na środowisko deweloperskie
Przykład użycia fazy install:
mvn installKażda z faz wywołuje poprzednią. Co oznacza, iż np. package wcześniej odpala validate, następnie compile i na końcu test. Dodatkowo można użyć też opcji clean, która usunie stare niepotrzebne pliki wygenerowane podczas poprzedniego budowania projektu (ale nie usunie Twojego kodu).
mvn clean installSekcje pliku pom.xml
Plik konfiguracyjny pom.xml posiada z góry ustaloną strukturę drzewiastą, podzieloną na odpowiednie tagi. Oto najważniejsze z nich:
project – główna sekcja, zawierająca wszystkie inne. Jest to sekcja minimum, aby zbudować projekt. Obowiązkowo powinna zawierać tagi: modelVersion (wersja deskryptora Mavena), groupId (grupa, do której powinna należeć Twoja aplikacja), artifactId (nazwa artefaktu, czyli Twojego programu) i version (w jakiej wersji jest Twój projekt).
dependencies – miejsce, w który wypisujesz wszystkie biblioteki potrzebne do pracy nad Twoim projektem. Biblioteki zostaną pobrane ze zdalnego repozytorium automatycznie i dołączone do Twojego kodu, tak, iż będziesz móc je używać jak zwykłe importy. Definiując zależności, podobnie jak w części głównej, wskazujesz grupę (groupId), artefakt (artifactId) oraz numer wersji biblioteki (version), którą chcesz pobrać. Możesz też opcjonalnie przypisać zakres (scope), w którym momencie cyklu życia zależność powinna zostać pobrana. Domyślnie zależności będą pobierane w fazie compile (czyli prawie najniższej), ale np. biblioteki do testowania mogą być pobieranie np. dopiero, gdy cykl osiągnie fazę test.
build – tag, w którym z reguły umieszcza się zestawienie wszelkich pluginów. Pozwala też pokazać miejsce przechowywania wszelkich zasobów (ang. resources).
plugins – ważna sekcja wewnątrz tagu build, zawiera konfigurację wtyczek, które będą uruchamiane podczas budowania aplikacji.
Struktura projektu
Nie tylko plik konfiguracyjny jest z góry ustalony. Projekty Maven posiadają też domyślne rozmieszczenie katalogów. Najczęściej używane z nich to:
src/main/java – miejsce przechowywania pakietów zawierających kod aplikacji
src/main/resources – zawiera zasoby potrzebne dla projektu (tu np. możesz trzymać skrypt tworzący bazę danych)
src/test/java – w tym katalogu powinny być zawarte testy jednostkowe
src/test/resources – zasoby dla testów
src/main/webapp – przydatne do aplikacji internetowych, np. do przechowywania plików HTML
Repozytoria
Teraz najważniejszą rzeczą dla Ciebie jest zrozumienie w jaki sposób zarządzane są zależności. Większość bibliotek, napisanych w Javie jest dostępnych na publicznych, zdalnych repozytoriach (czyli serwerach). Domyślnym z nich jest tzw. repozytorium centralne (central), dostępne pod adresem: https://repo1.maven.org/maven2/. To nie jedyny serwer tego typu. Całą ich listę znajdziesz na stronie: https://mvnrepository.com/repos. Dodatkowo wiele firm, ze względów bezpieczeństwa, tworzy własne repozytoria zdalne (zwane artifactory, od artifact). Tobie jednak na etapie nauki wystarczy wiedza o tym skąd są pobierane biblioteki oraz gdzie lokalnie są przechowywane.
Jeśli chcesz odnaleźć ściągnięte biblioteki, użyte w Twoim projekcie, to domyślnie znajdują się one w Twoim katalogu domowym w folderze ukrytym o nazwie .m2. W nim z kolei znajduje się Twoje lokalne repozytorium w katalogu o nazwie repository. jeżeli udało Ci się zbudować projekt dzięki komendy mvn install, to w tym miejscu będą widnieć zarówno zależności do Twojej aplikacji jak i ona sama.
Przykładowo na obrazku powyżej widać, iż została zaciągnięta biblioteka junit. Rozkład katalogów jest zbieżny z danymi w polach obowiązkowych w pliku pom.xml każdej z zależności, zgodnie z schematem groupId/artifactId/version. Ponieważ wartość groupId to 'junit’, po wyświetleniu folderu repository zobaczysz właśnie tą nazwę, a w niej znów katalog 'junit’, a następnie numer wersji (tutaj będzie to 3.8.1). W ten sposób Maven kataloguje sobie wszystkie biblioteki.
Nie inaczej dzieje się z moim projektem. Znajduję go pod ścieżką: pl/developeronthego/maven-test/1.0-SNAPSHOT/. W ten też sposób moja własna aplikacja, staje się też dostępna dla innych projektów, nad którymi pracuję lokalnie. Oczywiście, gdybym chciał podzielić się swoją biblioteką z innymi, musiałbym założyć swoje własne artifaktory i skonfigurować odpowiednio Mavena.
Konfiguracja
W katalogu .m2 znajdziesz nie tylko folder repository, ale także plik settings.xml, który kontroluje ustawienia Mavena. To właśnie tam możesz wskazać z jakiego serwera pobierane są zależności, czy ustawić proxy.
Sekcje w pliku settings.xml:
Servers – zawiera informacje wrażliwe (hasła, nazwy użytkowników) potrzebne do logowania się do zdalnego repozytorium, wskazanego w pom.xml (w tagu: <repositories>). Przydatne do pracy z wewnętrznym artifactory albo do pobierania dodatkowych bibliotek (np. w przypadku korzystania z frameworka Primefaces)
Mirrors – tutaj deklarujesz alternatywne do domyślnego repozytoria.
Proxies – ustawianie serwera proxy. Przydaje się, gdy komputer korzysta z zewnętrznego proxy. Często będziesz konfigurować tą opcję, gdy pracujesz z komputera pracowniczego.
Profiles – aby grupować powyższe ustawienia, warto ustawić odpowiednie profile, tak aby w łatwy sposób zamieniać jedne ustawienia na drugie. Przykładowo, pracujesz na dwóch projektach. Jeden korzysta z jednego repozytorium a drugi z innego.
ActiveProfiles – profile wypisane tutaj są automatycznie używane.
Jeśli chciałbyś manualnie wskazać, z którego profilu, to wystarczy użyć flagi -P.
mvn install -P githubNazwa github powinna być wypisana w tagu <id> w sekcji <profile>.
Przykładowy plik settings.xml
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> <activeProfiles> <activeProfile>github</activeProfile> </activeProfiles> <profiles> <profile> <id>github</id> <repositories> <repository> <id>central</id> <url>https://repo1.maven.org/maven2</url> </repository> <repository> <id>github</id> <url>https://maven.pkg.github.com/OWNER/REPOSITORY</url> <snapshots> <enabled>true</enabled> </snapshots> </repository> </repositories> </profile> </profiles> <servers> <server> <id>github</id> <username>USERNAME</username> <password>TOKEN</password> </server> </servers> </settings>Podsumowanie
Maven to wciąż najpopularniejszy framework do zarządzania projektem. Jego prostota sprawia, iż ciężko znaleźć do jego alternatywę, choć pod kątem samych możliwości przebija go np. Gradle. Warto jednak znać podstawy tego narzędzia, ponieważ szanse na spotkanie się z nim w projekcie komercyjnym są bardzo wysokie.
* Plik ten jest archiwum (podobnym do plików zip czy rar), zawierającym skompilowany kod projektu Java. Taki plik jest przenośny i umożliwia np. uruchamiane go dzięki serwerów aplikacji.
Przykładowy projekt, omawiany w lekcji: https://github.com/developeronthego/maven-test