Zanim zajmiemy się ANT, Mavenem lub Gradle, musimy najpierw zrozumieć kilka rzeczy z nimi związanych.
Zależność: Ogólnie rzecz biorąc, zależność odnosi się do sytuacji, gdy coś wymaga jakiejś innej rzeczy, aby wykonać się samo. Po prostu, „A” ma zależność od „B”, jeśli „A” wymaga „B” do jego pomyślnego wykonania. W świecie oprogramowania, zależność to cokolwiek, czego Twoja aplikacja wymaga do pomyślnego wykonania. Jest to w zasadzie każda zewnętrzna biblioteka pomocnicza wymagana przez aplikację. np. zuul, hystrix, lombok, jdbc, itp.
Początkowo zarządzaliśmy zależnościami poprzez:
- ręczne pobieranie pliku jar wymaganej biblioteki z Internetu i dodawanie go do naszego projektu.
- pisanie skryptu, który automatycznie pobierze bibliotekę z zewnętrznego źródła przez sieć.
Problemy napotykane przed tymi narzędziami:
- Dodawanie zależności poprzez ręczne pobieranie ich z internetu jest bardzo męczącym zadaniem.
- Nasze skrypty mogą zawieść, jeśli adres URL zewnętrznego źródła zmieni się w internecie.
- Bardzo trudno jest zidentyfikować i zarządzać zależnościami przechodnimi w naszej aplikacji.
Narzędzie do zarządzania zależnościami: Rozwiązuje i zarządza zależnościami wymaganymi przez aplikację.
Narzędzie do budowania: Automatyzuje tworzenie wykonywalnych aplikacji z kodu źródłowego. Budowanie obejmuje kompilację, łączenie i pakowanie kodu do postaci użytkowej lub wykonywalnej. Automatyzacja budowania obejmuje:
- Pobieranie zależności
- Kompilowanie kodu źródłowego do kodu binarnego
- Pakowanie tego kodu binarnego
- Robienie testów
- Wdrażanie do systemów produkcyjnych
Zarządzanie zależnościami i narzędzia budowania w języku java:
- ANT + Ivy (2000/2004)
- Maven (2004)
- Gradle (2012)
Apache ANT (Another Neat Tool) to projekt open source autorstwa Apache, wydany w 2000 roku. Jest to biblioteka java używana do automatyzacji procesów budowania aplikacji java. Może być również używana do budowania aplikacji nie-javowych. Działa zgodnie z zasadą „Konfiguracja ponad konwencją”. W Ant, różne fazy procesu budowania nazywane są „Celami”. Pliki budowania ANT są zapisywane w XML i umownie nazywane są „build.xml”. Zawiera on trzy elementy: projekt, cel i zadanie. Każdy plik buildowy zawiera jeden projekt. Każda pojedyncza rzecz w pliku build.xml znajduje się pod elementem project. Projekt zawiera co najmniej jeden cel (domyślnie). Cel zawiera zestaw zadań wewnątrz niego i definiuje konkretny stan procesu budowania. Zadanie jest fragmentem kodu, który może zostać wykonany. Każdy węzeł może posiadać atrybuty związane z nim:
Atrybuty projektu:
- Nazwa: Nazwa projektu.
- Basedir: Folder główny dla projektu i jest opcjonalny.
- Default: Domyślny cel dla kompilacji. Projekt może mieć jeden lub więcej celów. Jest on używany do określenia domyślnego celu projektu.
Atrybuty celu:
- Nazwa: Nazwa celu.
- Opis: Opis dotyczący celu.
- Depends: Lista wszystkich celów, oddzielonych przecinkami, od których ten cel zależy.
- Jeżeli: Cel jest wykonywany, jeśli atrybut jest prawdziwy.
- Unless: Cel jest wykonywany, jeśli atrybut nie jest ustawiony.
Build.xml przykład:
<?xml version="1.0"?>
<project>
<target name="hello">
<echo>Hello, World</echo>
</target>
</project>
Add dependency in Ant + Ivy:
<dependency org="org.projectlombok" name="lombok" rev="1.18.10"/>
Główną zaletą Ant jest jej elastyczność. Ant nie narzuca deweloperowi żadnych konwencji kodowania ani struktury projektu. W konsekwencji oznacza to, że Ant wymaga od deweloperów samodzielnego pisania wszystkich poleceń, co czasami prowadzi do dużych plików kompilacji i jest trudne do utrzymania. Początkowo, Ant nie posiadał wbudowanego wsparcia dla zarządzania zależnościami. Później zaadoptował Apache Ivy, opracowany jako podprojekt projektu Apache Ant, do celów zarządzania zależnościami.
Apache Maven
Jest to narzędzie do zarządzania zależnościami i automatyzacji budowania, wydane w 2004 roku. Nadal używa XML, ale przezwycięża jego wady poprzez stosowanie zasady „Konwencja ponad konfiguracją”. Opiera się na konwencjach i dostarcza predefiniowanych poleceń (celów). Jego plik konfiguracyjny, zawierający instrukcje budowania i zarządzania zależnościami, jest umownie nazywany „pom.xml” i znajduje się w katalogu głównym projektu.
Gdy w pliku pom.xml projektu określona jest zależność, maven szuka jej w lokalnym repozytorium. Jeśli nie zostanie tam znaleziona, szuka jej w repozytorium zdalnym/org wide. Jeśli nie ma go nawet tam, to szuka go w centralnym repozytorium.
Maven narzuca ścisłą strukturę projektu, podczas gdy Ant zapewnia elastyczność również w tym zakresie. Jego ścisłe konwencje mają cenę bycia o wiele mniej elastycznym niż Ant – dostosowanie celu jest bardzo trudne.
Wady maven:
- Zarządzanie zależnościami nie radzi sobie dobrze z konfliktami między różnymi wersjami tej samej biblioteki.
- Kustomizacja celów jest trudna.
Gradle
Jest to open-source’owe narzędzie do zarządzania zależnościami i automatyzacji budowania, wydane w 2012 roku. Łączy w sobie dobre części Apache Ant i Apache Maven i buduje na ich szczycie oraz używa języka specyficznego dla domeny (opartego na Groovy) zamiast XML. Przejął elastyczność z Anta i cykl życia z Mavena. Podąża również za zasadą „Konwencja ponad konfiguracją”. Obsługuje repozytoria Maven i Ivy do pobierania zależności. Jego plik konfiguracyjny jest umownie znany jako „build.gradle” i znajduje się w głównym folderze projektu. Gradle nadał swoim krokom budowania nazwę „zadania”, w przeciwieństwie do „celów” Ant’a lub „faz” Maven’a. Google przyjął Gradle jako domyślne narzędzie do budowania dla Android OS.
Gradle nie używa XML. Zamiast tego miał swój własny język specyficzny dla domeny oparty na Groovy (jeden z języków JVM). W rezultacie, skrypty budujące Gradle są znacznie krótsze i bardziej przejrzyste niż te napisane dla Ant lub Maven. Ilość kodu szablonowego jest znacznie mniejsza z Gradle.
Konfiguracje Gradle
- implementacja: Służy do deklarowania zależności, których nie chcemy narażać na czas kompilacji naszych konsumentów.
- api: Służy do deklarowania zależności, które są częścią naszego API, czyli dla zależności, które jawnie chcemy eksponować naszym konsumentom.
- compileOnly: Pozwala nam zadeklarować zależności, które powinny być dostępne tylko w czasie kompilacji, ale nie są potrzebne w czasie runtime. Przykładowym przypadkiem użycia tej konfiguracji jest procesor adnotacji taki jak Lombok, który modyfikuje kod bajtowy w czasie kompilacji. Po kompilacji nie jest to już potrzebne, więc zależność nie jest dostępna w czasie runtime.
- runtimeOnly: Pozwala nam zadeklarować zależności, które nie są potrzebne w czasie kompilacji, ale będą dostępne w czasie runtime. Przykładem jest SLF4J, gdzie dołączamy
slf4j-api
do konfiguracjiimplementation
, a implementację tego API (jakslf4j-log4j12
lublogback-classic
) do konfiguracjiruntimeOnly
. - testImplementation: Podobne do
implementation
, ale zależności zadeklarowane za pomocątestImplementation
są dostępne tylko podczas kompilacji i runtime’u testów. Możemy go użyć do zadeklarowania zależności do frameworków testujących takich jak JUnit czy Mockito, które są nam potrzebne tylko w testach i które nie powinny być dostępne w kodzie produkcyjnym. - testCompileOnly: Podobne do
compileOnly
, ale zależności zadeklarowane za pomocątestCompileOnly
są dostępne tylko podczas kompilacji testów, a nie w runtime. - testRuntimeOnly: Podobne do
runtimeOnly
, ale zależności zadeklarowane za pomocątestRuntimeOnly
są dostępne tylko podczas runtime’u testów, a nie w czasie kompilacji.
Projekty i zadania w Gradle
Każdy build Gradle składa się z jednego lub więcej projektów. Każdy projekt składa się z zestawu zadań. Każde zadanie reprezentuje pojedynczą część pracy, którą budujący wykonuje np. generuje JavaDoc, publikuje jakieś archiwa do repozytorium, itp.
build.gradle przykład
Gradle repozytorium:
„Aliasy” w Gradle są używane w przypadku dodawania repozytoriów Mavena do naszego projektu budującego. Aliasy te są następujące:
- mavenCentral(): Alias ten oznacza zależności, które są pobierane z centralnego repozytorium Maven 2.
- jcenter(): Ten alias oznacza zależności, które są pobierane z repozytorium Bintray’s JCenter Maven.
- mavenLocal(): Ten alias oznacza zależności, które są pobierane z lokalnego repozytorium Maven.
Przykład: dodaj centralne repozytorium Maven w naszym projekcie, dodaj następujący wycinek kodu do naszego pliku 'build.gradle’:
repositories {
mavenCentral()
}
Dodaj zależność w Gradle:
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
Zalety:
- Dość dobrze radzi sobie z zależnościami przechodnimi. Jeśli sprzeczna zależność przechodnia istnieje w projekcie, to aby ją rozwiązać, wybiera najnowszą wersję zależności. Na przykład, zależność „A” wewnętrznie wymaga zależności „C” w wersji 2.0, a zależność „B” wewnętrznie wymaga zależności „C” w wersji 3.0. Wtedy Gradle użyje najnowszej wersji zależności 'C’.
- Pliki konfiguracyjne Gradle’a mają mniejszy rozmiar i są czystsze, ponieważ używa języka specyficznego dla domeny, opartego na Groovy zamiast XML.
- Gradle używa koncepcji budowania przyrostowego i unika pracy poprzez śledzenie wejścia i wyjścia zadań i uruchamia tylko to, co jest konieczne, a także przetwarza tylko pliki, które się zmieniły, gdy jest to możliwe, a zatem działa szybciej niż maven.
.