Prima di entrare in ANT, Maven o Gradle, dobbiamo prima capire alcune cose relative ad essi: In generale, una dipendenza si riferisce a quando qualcosa richiede un’altra cosa per essere eseguita. In parole povere, ‘A’ ha una dipendenza da ‘B’ se ‘A’ richiede ‘B’ per la sua corretta esecuzione. Nel mondo del software, una dipendenza è qualsiasi cosa che la vostra applicazione richiede per la sua corretta esecuzione. E’ fondamentalmente qualsiasi libreria di supporto esterna richiesta dall’applicazione. es. zuul, hystrix, lombok, jdbc, ecc.
Inizialmente, eravamo soliti gestire le dipendenze:
- scaricando il file jar della libreria richiesta manualmente da internet e aggiungendolo al nostro progetto.
- scrivendo uno script che scarica automaticamente la libreria da una fonte esterna in rete.
Problemi affrontati prima di questi strumenti:
- Aggiungere le dipendenze scaricandole manualmente da internet è un compito molto faticoso.
- I nostri script potrebbero fallire se l’URL della fonte esterna cambia su internet.
- È molto difficile identificare e gestire le dipendenze transitive nella nostra applicazione.
Strumento di gestione delle dipendenze: Risolve e gestisce le dipendenze richieste dall’applicazione.
Strumento di costruzione: Automatizza la creazione di applicazioni eseguibili dal codice sorgente. La costruzione incorpora la compilazione, il collegamento e il confezionamento del codice in una forma utilizzabile o eseguibile. L’automazione della costruzione comporta:
- Scaricare le dipendenze
- Compilare il codice sorgente in codice binario
- Confezionare quel codice binario
- Eseguire i test
- Distribuzione ai sistemi di produzione
Gestione delle dipendenze e strumenti di costruzione in java:
- ANT + Ivy (2000/2004)
- Maven (2004)
- Gradle (2012)
Apache ANT (Another Neat Tool) è un progetto open source di Apache, rilasciato nel 2000. È una libreria java usata per automatizzare i processi di compilazione delle applicazioni java. Inoltre, può essere usato per costruire applicazioni non java. Segue il principio di “Configurazione sopra la convenzione”. In Ant, le diverse fasi del processo di compilazione sono chiamate “Targets”. I file di build di ANT sono scritti in XML e, per convenzione, sono chiamati “build.xml”. Contiene tre elementi: progetto, target e task. Ogni file di build contiene un progetto. Ogni singola cosa nel build.xml è sotto l’elemento project. Il progetto contiene almeno un target (predefinito). Il target contiene un insieme di compiti al suo interno e definisce uno stato specifico del processo di compilazione. Un task è un pezzo di codice che può essere eseguito. Ogni nodo può avere attributi associati:
Attributi del progetto:
- Nome: Il nome del progetto.
- Basedir: La cartella principale del progetto ed è opzionale.
- Default: L’obiettivo predefinito per la costruzione. Il progetto può avere uno o più target. Viene usato per specificare il target di default del progetto.
Attributi di Target:
- Name: Il nome del target.
- Descrizione: Una descrizione dell’obiettivo.
- Dipende: Elenco di tutti gli obiettivi, separati da virgola, da cui questo obiettivo dipende.
- If: L’obiettivo viene eseguito se l’attributo è vero.
- Unless: L’obiettivo viene eseguito se l’attributo non è impostato.
Esempio di build.xml:
<?xml version="1.0"?>
<project>
<target name="hello">
<echo>Hello, World</echo>
</target>
</project>
Aggiungi dipendenza in Ant + Ivy:
<dependency org="org.projectlombok" name="lombok" rev="1.18.10"/>
Il principale vantaggio di Ant è la sua flessibilità. Ant non impone alcuna convenzione di codifica o struttura di progetto allo sviluppatore. Di conseguenza, questo significa che Ant richiede agli sviluppatori di scrivere tutti i comandi da soli, il che a volte porta a file di build grandi e difficili da mantenere. Inizialmente, Ant non aveva alcun supporto integrato per la gestione delle dipendenze. Più tardi ha adottato Apache Ivy, sviluppato come sottoprogetto del progetto Apache Ant, allo scopo di gestire le dipendenze.
Apache Maven
È uno strumento di gestione delle dipendenze e di automazione della compilazione, rilasciato nel 2004. Continua ad usare XML, ma supera gli svantaggi seguendo il principio “Convention over configuration”. Si basa su convenzioni e fornisce comandi predefiniti (obiettivi). Il suo file di configurazione, che contiene istruzioni per la compilazione e la gestione delle dipendenze, si chiama per convenzione “pom.xml” ed è presente nella cartella principale del progetto.
Maven engine prende pom.xml e il progetto come input. Legge il file pom.xml e scarica le dipendenze menzionate in esso come file jar nel repository locale. Poi, esegue i cicli di vita, le fasi di costruzione e i plugin. Alla fine, viene generato un artefatto confezionato e testato.
esempio pom.xml:
Alcuni tag importanti nel file pom.xml:
- groupId: Rappresenta l’organizzazione a cui appartiene il progetto.
- artifactId: È il nome del progetto.
- version: Rappresenta la versione del progetto.
- packaging: Rappresenta la forma finale della build del progetto. ad esempio jar, war.
Aggiungi dipendenza in maven:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
</dependency>
Repository di Maven:
Un repository è una directory dove esistono tutti i file jar pacchettizzati insieme ai loro file pom. Questi file pom contengono le dipendenze esterne di quel progetto. In questo modo maven scarica le dipendenze delle dipendenze del tuo progetto in modo ricorsivo fino a quando tutte le dipendenze richieste sono presenti nel tuo repository locale. Ci sono tre tipi di repository in maven:
- Repository locale: È un repository presente sulla macchina dello sviluppatore stesso.
- Livello di organizzazione/repository remoto: È un repository presente all’interno dell’organizzazione.
- Repository centrale: È un repository su internet, creato e mantenuto dalla comunità maven.
Quando una dipendenza è specificata nel file pom.xml di un progetto, maven la cerca nel repository locale. Se non la trova lì, la cerca nel repository remoto/org wide. Se non è presente nemmeno lì, allora lo cerca nel repository centrale.
Maven prescrive una struttura di progetto rigida, mentre Ant fornisce flessibilità anche lì. Le sue rigide convenzioni hanno il prezzo di essere molto meno flessibili di Ant – la personalizzazione dell’obiettivo è molto difficile.
Svantaggi di maven:
- La gestione delle dipendenze non gestisce bene i conflitti tra diverse versioni della stessa libreria.
- La personalizzazione degli obiettivi è difficile.
Gradle
È uno strumento open-source di gestione delle dipendenze e automazione della compilazione, rilasciato nel 2012. Combina le parti buone di Apache Ant e Apache Maven e costruisce sopra di loro e usa un linguaggio specifico del dominio (basato su Groovy) invece di XML. Ha adottato la flessibilità da Ant e il suo ciclo di vita da Maven. Segue anche il principio della “convenzione sulla configurazione”. Supporta i repository Maven e Ivy per recuperare le dipendenze. Il suo file di configurazione è per convenzione conosciuto come “build.gradle” ed è presente nella cartella principale del progetto. Gradle ha dato ai suoi passi di compilazione il nome di “task”, al contrario dei “target” di Ant o delle “fasi” di Maven. Google ha adottato Gradle come strumento di compilazione predefinito per Android OS.
Gradle non usa XML. Invece, ha il proprio linguaggio specifico di dominio basato su Groovy (uno dei linguaggi JVM). Come risultato, gli script di compilazione di Gradle tendono ad essere molto più brevi e chiari di quelli scritti per Ant o Maven. La quantità di codice boilerplate è molto più piccola con Gradle.
Configurazioni Gradle
- implementazione: È usato per dichiarare le dipendenze che non vogliamo esporre al tempo di compilazione dei nostri consumatori.
- api: Si usa per dichiarare le dipendenze che fanno parte della nostra API, cioè per le dipendenze che vogliamo esplicitamente esporre ai nostri consumatori.
- compileOnly: Ci permette di dichiarare dipendenze che dovrebbero essere disponibili solo in fase di compilazione, ma che non sono necessarie in fase di esecuzione. Un esempio di caso d’uso per questa configurazione è un processore di annotazioni come Lombok, che modifica il bytecode in fase di compilazione. Dopo la compilazione non è più necessario, quindi la dipendenza non è disponibile a runtime.
- runtimeOnly: Ci permette di dichiarare dipendenze che non sono necessarie in fase di compilazione, ma saranno disponibili in fase di esecuzione. Un esempio è SLF4J dove includiamo
slf4j-api
alla configurazioneimplementation
e un’implementazione di quella API (comeslf4j-log4j12
ologback-classic
) alla configurazioneruntimeOnly
. - testImplementation: Simile a
implementation
, ma le dipendenze dichiarate contestImplementation
sono disponibili solo durante la compilazione e l’esecuzione dei test. Possiamo usarlo per dichiarare dipendenze da framework di test come JUnit o Mockito che ci servono solo nei test e che non dovrebbero essere disponibili nel codice di produzione. - testCompileOnly: Simile a
compileOnly
, ma le dipendenze dichiarate contestCompileOnly
sono disponibili solo durante la compilazione dei test e non a runtime. - testRuntimeOnly: Simile a
runtimeOnly
, ma le dipendenze dichiarate contestRuntimeOnly
sono disponibili solo durante l’esecuzione dei test e non in fase di compilazione.
Progetti e compiti in Gradle
Ogni build di Gradle consiste in uno o più progetti. Ogni progetto consiste in un insieme di compiti. Ogni compito rappresenta un singolo pezzo di lavoro che una build esegue, ad esempio generare JavaDoc, pubblicare alcuni archivi in un repository, ecc.
esempio dibuild.gradle
Repository Gradle:
Gradle repository:
Gli “alias” in Gradle sono usati in caso di aggiunta di repository Maven al nostro progetto di build. Questi alias sono i seguenti:
- mavenCentral(): Questo alias sta per le dipendenze che sono recuperate dal repository centrale di Maven 2.
- jcenter(): Questo alias sta per le dipendenze che sono recuperate dal repository JCenter Maven di Bintray.
- mavenLocal(): Questo alias sta per le dipendenze che sono recuperate dal repository Maven locale.
Esempio: aggiungere il repository Maven centrale nel nostro progetto, aggiungere il seguente frammento di codice al nostro file ‘build.gradle’:
repositories {
mavenCentral()
}
Aggiungi dipendenza in Gradle:
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
Avantaggi:
- Gestisce le dipendenze transitive abbastanza bene. Se esiste una dipendenza transitiva conflittuale nel progetto, allora per risolverla, seleziona l’ultima versione della dipendenza. Per esempio, la dipendenza ‘A’ richiede internamente la dipendenza ‘C’ con la versione 2.0 e la dipendenza ‘B’ richiede internamente la dipendenza ‘C’ con la versione 3.0. Allora Gradle userà l’ultima versione della dipendenza ‘C’.
- I file di configurazione di Gradle sono di dimensioni più piccole e più puliti in quanto utilizza un linguaggio specifico del dominio, basato su Groovy invece di XML.
- Gradle usa il concetto di build incrementale ed evita il lavoro tracciando l’input e l’output dei compiti ed eseguendo solo ciò che è necessario, e processando solo i file che sono cambiati quando possibile e quindi, esegue più velocemente di maven.