Introduction à Gradle

Cet article fait partie d'une série: • Introduction à Gradle (article actuel) • Ant vs Maven vs Gradle

• Écriture de plugins Gradle personnalisés

• Créer un Fat Jar dans Gradle

1. Vue d'ensemble

Gradle est un système de gestion de build basé sur Groovy conçu spécifiquement pour la création de projets Java.

Les instructions d'installation peuvent être trouvées ici.

2. Blocs de construction - Projets et tâches

Dans Gradle, les builds consistent en un ou plusieurs projets et chaque projet se compose d'une ou plusieurs tâches.

Un projet dans Gradle peut être l'assemblage d'un fichier jar , war ou même zip .

Une tâche est un seul travail. Cela peut inclure la compilation de classes ou la création et la publication d'archives Java / Web.

Une tâche simple peut être définie comme:

task hello { doLast { println 'Baeldung' } }

Si nous exécutons la tâche ci-dessus en utilisant la commande gradle -q hello à partir du même emplacement où se trouve build.gradle , nous devrions voir la sortie dans la console.

2.1. Tâches

Les scripts de construction de Gradle ne sont rien d'autre que Groovy:

task toLower { doLast { String someString = 'HELLO FROM BAELDUNG' println "Original: "+ someString println "Lower case: " + someString.toLowerCase() } }

Nous pouvons définir des tâches qui dépendent d'autres tâches. La dépendance de tâche peut être définie en passant l' argument dependOn: taskName dans une définition de tâche:

task helloGradle { doLast { println 'Hello Gradle!' } } task fromBaeldung(dependsOn: helloGradle) { doLast { println "I'm from Baeldung" } }

2.2. Ajout d'un comportement à une tâche

Nous pouvons définir une tâche et l'améliorer avec un comportement supplémentaire:

task helloBaeldung { doLast { println 'I will be executed second' } } helloBaeldung.doFirst { println 'I will be executed first' } helloBaeldung.doLast { println 'I will be executed third' } helloBaeldung { doLast { println 'I will be executed fourth' } }

doFirst et doLast ajoutent des actions en haut et en bas de la liste d'actions, respectivement, et peuvent être définies plusieurs fois dans une seule tâche .

2.3. Ajout de propriétés de tâche

Nous pouvons également définir des propriétés:

task ourTask { ext.theProperty = "theValue" } 

Ici, nous mettons « theValue » comme theProperty de la ourTask tâche.

3. Gestion des plugins

Il existe deux types de plugins dans Gradle: script et binaire.

Pour bénéficier d'une fonctionnalité supplémentaire, chaque plugin doit passer par deux phases: la résolution et l' application.

Résoudre signifie trouver la version correcte du fichier jar du plugin et l'ajouter au chemin de classe du projet.

L'application de plugins exécute Plugin.apply (T) sur le projet .

3.1. Application de plugins de script

Dans aplugin.gradle, nous pouvons définir une tâche:

task fromPlugin { doLast { println "I'm from plugin" } }

Si nous voulons appliquer ce plugin à notre fichier build.gradle de projet , tout ce que nous devons faire est d'ajouter cette ligne à notre build.gradle :

apply from: 'aplugin.gradle' 

Maintenant, l'exécution de la commande gradle tasks devrait afficher la tâche fromPlugin dans la liste des tâches.

3.2. Application de plugins binaires à l'aide de plugins DSL

Dans le cas de l'ajout d'un plugin binaire principal, nous pouvons ajouter des noms courts ou un identifiant de plugin:

plugins { id 'application' }

Désormais, la tâche d' exécution du plugin d' application devrait être disponible dans un projet pour exécuter n'importe quel fichier jar exécutable . Pour appliquer un plugin communautaire, nous devons mentionner un identifiant de plugin complet:

plugins { id "org.shipkit.bintray" version "0.9.116" }

Désormais, les tâches Shipkit devraient être disponibles dans la liste des tâches gradle .

Les limitations des plugins DSL sont:

  • Il ne prend pas en charge le code Groovy dans le bloc des plugins
  • Le bloc plugins doit être l'instruction de niveau supérieur dans les scripts de construction du projet (seul le bloc buildscripts {} est autorisé avant lui)
  • Les plugins DSL ne peuvent pas être écrits dans le plugin de scripts, le fichier settings.gradle ou dans les scripts d'initialisation

Plugins DSL est toujours en incubation. La DSL et d'autres configurations peuvent changer dans les versions ultérieures de Gradle.

3.3. Procédure héritée pour l'application de plugins

Nous pouvons également appliquer des plugins en utilisant le «plugin apply» :

apply plugin: 'war'

Si nous devons ajouter un plugin de communauté, nous devons ajouter le fichier jar externe au chemin de classe de construction en utilisant le bloc buildscript {} .

Then, we can apply the plugin in the build scripts butonly after any existing plugins{} block:

buildscript { repositories { maven { url "//plugins.gradle.org/m2/" } } dependencies { classpath "org.shipkit:shipkit:0.9.117" } } apply plugin: "org.shipkit.bintray-release"

4. Dependency Management

Gradle supports very flexible dependency management system, it's compatible with the wide variety of available approaches.

Best practices for dependency management in Gradle are versioning, dynamic versioning, resolving version conflicts and managing transitive dependencies.

4.1. Dependency Configuration

Dependencies are grouped into different configurations. A configuration has a name and they can extend each other.

If we apply the Java plugin, we'll have compile, testCompile, runtime configurations available for grouping our dependencies. The default configuration extends “runtime”.

4.2. Declaring Dependencies

Let's look at an example of adding some dependencies (Spring and Hibernate) using several different ways:

dependencies { compile group: 'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE' compile 'org.springframework:spring-core:4.3.5.RELEASE', 'org.springframework:spring-aop:4.3.5.RELEASE' compile( [group: 'org.springframework', name: 'spring-core', version: '4.3.5.RELEASE'], [group: 'org.springframework', name: 'spring-aop', version: '4.3.5.RELEASE'] ) testCompile('org.hibernate:hibernate-core:5.2.12.Final') { transitive = true } runtime(group: 'org.hibernate', name: 'hibernate-core', version: '5.2.12.Final') { transitive = false } }

We're declaring dependencies in various configurations: compile, testCompile, and runtime in various formats.

Sometimes we need dependencies that have multiple artifacts. In such cases, we can add an artifact-only notations @extensionName (or ext in the expanded form) to download the desired artifact:

runtime "org.codehaus.groovy:groovy-all:[email protected]" runtime group: 'org.codehaus.groovy', name: 'groovy-all', version: '2.4.11', ext: 'jar'

Here, we added the @jar notation to download only the jar artifact without the dependencies.

To add dependencies to any local files, we can use something like this:

compile files('libs/joda-time-2.2.jar', 'libs/junit-4.12.jar') compile fileTree(dir: 'libs', include: '*.jar')

When we want to avoid transitive dependencies,we can do it on configuration level or on dependency level:

configurations { testCompile.exclude module: 'junit' } testCompile("org.springframework.batch:spring-batch-test:3.0.7.RELEASE"){ exclude module: 'junit' }

5. Multi-Project Builds

5.1. Build Lifecycle

In the initialization phase, Gradle determines which projects are going to take part in a multi-project build.

This is usually mentioned in settings.gradle file, which is located in the project root. Gradle also creates instances of the participating projects.

In the configuration phase, all created projects instances are configured based on Gradle feature configuration on demand.

In this feature, only required projects are configured for a specific task execution. This way, configuration time is highly reduced for a large multi-project build. This feature is still incubating.

Finally, in the execution phase, a subset of tasks, created and configured are executed. We can include code in the settings.gradle and build.gradle files to perceive these three phases.

In settings.gradle :

println 'At initialization phase.'

In build.gradle :

println 'At configuration phase.' task configured { println 'Also at the configuration phase.' } task execFirstTest { doLast { println 'During the execution phase.' } } task execSecondTest { doFirst { println 'At first during the execution phase.' } doLast { println 'At last during the execution phase.' } println 'At configuration phase.' }

5.2. Creating Multi-Project Build

We can execute the gradle init command in the root folder to create a skeleton for both settings.gradle and build.gradle file.

All common configuration will be kept in the root build script:

allprojects { repositories { mavenCentral() } } subprojects { version = '1.0' }

The setting file needs to include root project name and subproject name:

rootProject.name = 'multi-project-builds' include 'greeting-library','greeter'

Now we need to have a couple of subproject folders named greeting-library and greeter to have a demo of a multi-project build. Each subproject needs to have an individual build script to configure their individual dependencies and other necessary configurations.

If we'd like to have our greeter project dependent on the greeting-library, we need to include the dependency in the build script of greeter:

dependencies { compile project(':greeting-library') }

6. Using Gradle Wrapper

If a Gradle project has gradlew file for Linux and gradlew.bat file for Windows, we don't need to install Gradle to build the project.

If we execute gradlew build in Windows and ./gradlew build in Linux, a Gradle distribution specified in gradlew file will be downloaded automatically.

If we'd like to add the Gradle wrapper to our project:

gradle wrapper --gradle-version 4.2.1

The command needs to be executed from the root of the project. This will create all necessary files and folders to tie Gradle wrapper to the project. The other way to do the same is to add the wrapper task to the build script:

task wrapper(type: Wrapper) { gradleVersion = '4.2.1' }

Nous devons maintenant exécuter la tâche wrapper et la tâche liera notre projet au wrapper. Outre les fichiers gradlew , un dossier wrapper est généré à l'intérieur du dossier gradle contenant un fichier jar et un fichier de propriétés.

Si nous voulons passer à une nouvelle version de Gradle, nous avons seulement besoin de changer une entrée dans gradle- wrapper.properties .

7. Conclusion

Dans cet article, nous avons examiné Gradle et avons vu qu'il offre une plus grande flexibilité par rapport aux autres outils de construction existants en termes de résolution des conflits de version et de gestion des dépendances transitives.

Le code source de cet article est disponible à l'adresse over sur GitHub.

Suivant » Ant vs Maven vs Gradle