Hvor vi går ind i ANT, Maven eller Gradle, skal vi først forstå nogle få ting, der er relateret til dem.
Afhængighed: Generelt henviser en afhængighed til, når noget kræver en anden ting for at blive eksekveret selv. Enkelt sagt har “A” en afhængighed af “B”, hvis “A” kræver “B” for at kunne blive udført med succes. I softwareverdenen er en afhængighed alt det, som din applikation kræver, for at den kan udføres med succes. Det er dybest set ethvert eksternt støttebibliotek, der kræves af programmet. f.eks. zuul, hystrix, lombok, jdbc osv.
I første omgang plejede vi at håndtere afhængigheder ved:
- at downloade jar-filen med det nødvendige bibliotek manuelt fra internettet og tilføje den til vores projekt.
- at skrive et script, der automatisk henter biblioteket fra en ekstern kilde over netværket.
Problemer, som vi står over for før disse værktøjer:
- At tilføje afhængighederne ved manuelt at downloade dem fra internettet er en meget trættende opgave.
- Vores scripts kan mislykkes, hvis URL’en for den eksterne kilde ændres over internettet.
- Det er meget vanskeligt at identificere og administrere de transitive afhængigheder i vores applikation.
Dependency management tool: Det løser og administrerer de afhængigheder, der kræves af applikationen.
Build-værktøj: Dette værktøj løser og administrerer de afhængigheder, der kræves af applikationen: Det automatiserer oprettelsen af eksekverbare applikationer fra kildekoden. Opbygning omfatter kompilering, sammenkobling og pakning af koden til en brugbar eller eksekverbar form. Automatisering af opbygning omfatter:
- Download af afhængigheder
- Kompilering af kildekode til binær kode
- Pakning af denne binære kode
- Kørsel af tests
- Deployering til produktionssystemer
Dependency management and build tools in java:
- ANT + Ivy (2000/2004)
- Maven (2004)
- Gradle (2012)
Apache ANT (Another Neat Tool) er et open source-projekt fra Apache, der blev udgivet i år 2000. Det er et java-bibliotek, der bruges til at automatisere byggeprocesserne for java-applikationer. Det kan også bruges til at bygge ikke-java-programmer. Det følger princippet om “Configuration over convention”. I Ant kaldes de forskellige faser i opbygningsprocessen for “Targets” (mål). ANT-bygningsfiler er skrevet i XML, og efter konvention kaldes de “build.xml”. Den indeholder tre elementer: projekt, mål og opgave. Hver build-fil indeholder ét projekt. Hver eneste ting i build.xml er under projektelementet. Projekt indeholder mindst ét mål (standard). Target indeholder et sæt opgaver indeni og definerer en bestemt tilstand i byggeprocessen. En opgave er et stykke kode, som kan udføres. Hver node kan have attributter knyttet til sig:
Attributter for projekt:
- Navn:
- Basedir: Projektets navn: Det er valgfrit.
- Default: Projektets rodmappe: Standardmålet for opbygningen. Projektet kan have et eller flere antal mål. Det bruges til at angive projektets standardmål.
Attributter for mål:
- Navn:
- Beskrivelse: Navnet på målet.
- Beskrivelse: En beskrivelse af målet.
- Afhænger:
- Liste over alle mål, adskilt af kommaer, som dette mål afhænger af.
- If: Hvis: Målet udføres, hvis attributten er sand.
- Medmindre: Målet udføres, hvis attributten er sand: Målet udføres, hvis attributten ikke er angivet.
Build.xml eksempel:
<?xml version="1.0"?>
<project>
<target name="hello">
<echo>Hello, World</echo>
</target>
</project>
Tilføj afhængighed i Ant + Ivy:
<dependency org="org.projectlombok" name="lombok" rev="1.18.10"/>
Den største fordel ved Ant er dens fleksibilitet. Ant pålægger ikke udvikleren nogen kodningskonventioner eller projektstruktur. Det betyder følgelig, at Ant kræver, at udviklerne selv skal skrive alle kommandoer, hvilket nogle gange fører til store build-filer og er svære at vedligeholde. Oprindeligt havde Ant ingen indbygget understøttelse af afhængighedsstyring. Senere overtog det Apache Ivy, der er udviklet som et underprojekt til Apache Ant-projektet, med henblik på afhængighedsstyring.
Apache Maven
Det er et værktøj til afhængighedsstyring og byggeautomatisering, der blev frigivet i 2004. Det fortsætter med at bruge XML, men overvinder ulemperne ved at følge princippet om “Convention over configuration”. Det baserer sig på konventioner og giver foruddefinerede kommandoer (mål). Dens konfigurationsfil, der indeholder bygge- og afhængighedsstyringsinstruktioner, kaldes ved konvention “pom.xml” og findes i projektets rodmappe.
Maven engine tager pom.xml og projektet som inddata. Den læser pom.xml-filen og downloader de afhængigheder, der er nævnt i den, som jar-filer til det lokale repository. Derefter udfører den livscyklusser, byggefaser og plugins. Til sidst genereres et pakket og testet artefakt.
pom.xml eksempel:
Nogle vigtige tags i pom.xml-filen:
- groupId: Det repræsenterer den organisation, som projektet tilhører.
- artifactId:
- artefactId: Det er navnet på projektet.
- version:
- version: Det repræsenterer projektets version.
- packaging: Det repræsenterer den endelige form for build af projektet. f.eks. jar, war.
Tilføj afhængighed i maven:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
Maven repository:
Et repository er en mappe, hvor alle de pakkede jar-filer findes sammen med deres egne pom-filer. Disse pom-filer indeholder de eksterne afhængigheder for det pågældende projekt. På denne måde downloader maven afhængigheder af afhængigheder i dit projekt rekursivt, indtil alle de nødvendige afhængigheder er til stede i dit lokale repository. Der er tre typer af repositorier i maven:
- Lokalt repositorium:
- Organisationsniveau/fjernrepositorium: Det er et repository, der findes på udviklerens egen maskine: Det er et repository, der findes i organisationen.
- Centralt repository: Det er et repository over internettet, der er oprettet og vedligeholdes af maven-fællesskabet.
Når en afhængighed er angivet i pom.xml-filen for et projekt, søger maven efter den i det lokale repository. Hvis den ikke findes der, søger den efter den i det eksterne/org-wide repository. Hvis den heller ikke findes der, søger den efter den i det centrale repository.
Maven foreskriver en streng projektstruktur, mens Ant også der giver fleksibilitet. Dens strenge konventioner kommer med den pris, at den er meget mindre fleksibel end Ant – måltilpasning er meget svær.
Ulemper ved maven:
- Dependency management håndterer ikke konflikter godt mellem forskellige versioner af det samme bibliotek.
- Anpasning af mål er svært.
Gradle
Det er et open source-værktøj til afhængighedsstyring og byggeautomatisering, der blev udgivet i 2012. Det kombinerer de gode dele af Apache Ant og Apache Maven og bygger oven på dem og bruger et domænespecifikt sprog (baseret på Groovy) i stedet for XML. Det har overtaget fleksibilitet fra Ant og sin livscyklus fra Maven. Den følger også princippet om “konvention frem for konfiguration”. Den understøtter Maven- og Ivy-repositorier til at hente afhængigheder. Konfigurationsfilen er som konvention kendt som “build.gradle” og findes i projektets rodmappe. Gradle har givet sine opbygningstrin navnet “tasks”, i modsætning til Ant’s “targets” eller Maven’s “phases”. Google har vedtaget Gradle som standard build-værktøj til Android OS.
Gradle bruger ikke XML. I stedet havde det sit eget domænespecifikke sprog baseret på Groovy (et af JVM-sprogene). Som følge heraf har Gradle-byggescripts tendens til at være meget kortere og klarere end dem, der er skrevet til Ant eller Maven. Mængden af boilerplate-kode er meget mindre med Gradle.
Gradle-konfigurationer
- implementering: Det bruges til at erklære afhængigheder, som vi ikke ønsker at eksponere for vores forbrugeres kompileringstid.
- api: Det bruges til at erklære afhængigheder, der er en del af vores API, dvs. til afhængigheder, som vi udtrykkeligt ønsker at eksponere for vores forbrugere.
- compileOnly: Det giver os mulighed for at deklarere afhængigheder, der kun skal være tilgængelige på kompileringstidspunktet, men som ikke er nødvendige på køretid. Et eksempel på et brugsscenarie for denne konfiguration er en annotationsprocessor som Lombok, der ændrer bytekoden på kompileringstidspunktet. Efter kompilering er der ikke længere brug for den, så afhængigheden er ikke tilgængelig ved kørselstid.
- runtimeOnly: Det giver os mulighed for at erklære afhængigheder, der ikke er nødvendige på kompileringstidspunktet, men som vil være tilgængelige ved kørselstid. Et eksempel er SLF4J, hvor vi inkluderer
slf4j-api
tilimplementation
-konfigurationen og en implementering af dette API (somslf4j-log4j12
ellerlogback-classic
) tilruntimeOnly
-konfigurationen. - testImplementation: Svarer til
implementation
, men afhængigheder, der er angivet medtestImplementation
, er kun tilgængelige under kompilering og kørsel af test. Vi kan bruge den til at deklarere afhængigheder til testframeworks som JUnit eller Mockito, som vi kun har brug for i tests, og som ikke skal være tilgængelige i produktionskoden. - testRuntimeOnly: Svarer til
runtimeOnly
, men afhængigheder, der er angivet medtestRuntimeOnly
, er kun tilgængelige under kørselstid for test og ikke på kompileringstidspunktet.
testCompileOnly: Svarer til compileOnly
, men afhængigheder, der er deklareret med testCompileOnly
, er kun tilgængelige under kompilering af test og ikke ved kørsel.
Projekter og opgaver i Gradle
Alle Gradle-bygninger består af et eller flere projekter. Hvert projekt består af et sæt opgaver. Hver opgave repræsenterer et enkelt stykke arbejde, som et build udfører, f.eks. generere JavaDoc, udgive nogle arkiver til et repository osv.
build.gradle eksempel
Gradle-repository:
“Aliasserne” i Gradle bruges i tilfælde af at tilføje Maven-repositories til vores projekt build. Disse aliaser er som følger:
- mavenCentral(): Dette alias står for de afhængigheder, der hentes fra det centrale Maven 2-repositorium.
- jcenter():
- jcenter(): Dette alias står for de afhængigheder, der hentes fra det centrale Maven 2-repositorium: Dette alias står for de afhængigheder, der hentes fra Bintrays JCenter Maven-repository.
- mavenLocal(): Dette alias står for de afhængigheder, der hentes fra Bintrays JCenter Maven-repository.
- mavenLocal(): Dette alias står for de afhængigheder, der hentes fra det lokale Maven-repositorium.
Eksempel: Tilføj det centrale Maven-repositorium i vores projekt, tilføj følgende kodestykke til vores ‘build.gradle’-fil:
repositories {
mavenCentral()
}
Tilføj afhængighed i Gradle:
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
Fordele:
- Det håndterer transitive afhængigheder ret godt. Hvis der findes en konfliktende transitiv afhængighed i projektet, vælger den den nyeste version af afhængigheden for at løse den. For eksempel kræver afhængighed “A” internt afhængighed “C” med version 2.0, og afhængighed “B” kræver internt afhængighed “C” med version 3.0. Så vil Gradle bruge den nyeste version af afhængighed ‘C’.
- Gradles konfigurationsfiler er mindre i størrelse og mere rene, da den bruger domænespecifikt sprog, baseret på Groovy i stedet for XML.
- Gradle bruger inkrementelt opbygningskoncept og undgår arbejde ved at spore input og output af opgaver og kun køre det, der er nødvendigt, og kun behandle filer, der er ændret, når det er muligt, og derfor udfører den hurtigere end maven.