Einführung in Gradle

Dieser Artikel ist Teil einer Reihe: • Einführung in Gradle (aktueller Artikel) • Ant vs Maven vs Gradle

• Schreiben von benutzerdefinierten Gradle-Plugins

• Erstellen eines Fat Jar in Gradle

1. Übersicht

Gradle ist ein Groovy-basiertes Build-Management-System, das speziell für die Erstellung von Java-basierten Projekten entwickelt wurde.

Installationsanweisungen finden Sie hier.

2. Bausteine ​​- Projekte und Aufgaben

In Gradle bestehen Builds aus einem oder mehreren Projekten und jedes Projekt besteht aus einer oder mehreren Aufgaben.

Ein Projekt in Gradle kann ein Glas , einen Krieg oder sogar eine Zip- Datei zusammenstellen.

Eine Aufgabe ist eine einzelne Arbeit. Dies kann das Kompilieren von Klassen oder das Erstellen und Veröffentlichen von Java / Webarchiven umfassen.

Eine einfache Aufgabe kann definiert werden als:

task hello { doLast { println 'Baeldung' } }

Wenn wir die obige Aufgabe mit dem Befehl gradle -q hello an derselben Stelle ausführen , an der sich build.gradle befindet, sollte die Ausgabe in der Konsole angezeigt werden .

2.1. Aufgaben

Gradles Build-Skripte sind nichts anderes als Groovy:

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

Wir können Aufgaben definieren, die von anderen Aufgaben abhängen. Die Aufgabenabhängigkeit kann definiert werden, indem das Argument " definedOn: taskName" in einer Aufgabendefinition übergeben wird:

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

2.2. Hinzufügen von Verhalten zu einer Aufgabe

Wir können eine Aufgabe definieren und durch zusätzliches Verhalten erweitern:

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 und doLast fügen Aktionen oben und unten in der Aktionsliste hinzu und können in einer einzelnen Aufgabe mehrmals definiert werden .

2.3. Hinzufügen von Aufgabeneigenschaften

Wir können auch Eigenschaften definieren:

task ourTask { ext.theProperty = "theValue" } 

Hier setzen wir "theValue" als die Eigenschaft der ourTask- Aufgabe.

3. Plugins verwalten

Es gibt zwei Arten von Plugins in Gradle - Skript und Binär.

Um von einer zusätzlichen Funktionalität zu profitieren, muss jedes Plugin zwei Phasen durchlaufen: Auflösen und Anwenden.

Das Auflösen bedeutet, die richtige Version des Plugin-JAR zu finden und diese dem Klassenpfad des Projekts hinzuzufügen .

Durch das Anwenden von Plugins wird Plugin.apply (T) für das Projekt ausgeführt .

3.1. Anwenden von Skript-Plugins

In der Datei aplugin.gradle können wir eine Aufgabe definieren:

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

Wenn wir dieses Plugin auf unsere Projektdatei build.gradle anwenden möchten , müssen wir diese Zeile nur zu unserer build.gradle hinzufügen :

apply from: 'aplugin.gradle' 

Wenn Sie nun den Befehl gradle task ausführen, sollte die Aufgabe fromPlugin in der Aufgabenliste angezeigt werden .

3.2. Anwenden von binären Plugins mit Plugins DSL

Beim Hinzufügen eines binären Kern-Plugins können wir Kurznamen oder eine Plugin-ID hinzufügen:

plugins { id 'application' }

Jetzt sollte die Ausführungsaufgabe vom Anwendungs- Plugin in einem Projekt verfügbar sein, um alle ausführbaren JARs auszuführen . Um ein Community-Plugin anzuwenden, müssen wir eine vollständig qualifizierte Plugin-ID angeben:

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

Jetzt sollten Shipkit-Aufgaben in der Liste der Gradle- Aufgaben verfügbar sein .

Die Einschränkungen der Plugins DSL sind:

  • Groovy-Code im Plugins- Block wird nicht unterstützt
  • Der Plugins- Block muss die Anweisung der obersten Ebene in den Build-Skripten des Projekts sein (nur der Buildscripts {} -Block ist davor zulässig).
  • Plugins DSL kann nicht in das Skript-Plugin, die Datei settings.gradle oder in Init-Skripte geschrieben werden

Plugins DSL inkubiert noch. Das DSL und andere Konfigurationen können sich in späteren Gradle-Versionen ändern.

3.3. Legacy-Verfahren zum Anwenden von Plugins

Wir können Plugins auch mit dem "Apply Plugin" anwenden :

apply plugin: 'war'

Wenn wir ein Community-Plugin hinzufügen müssen, müssen wir das externe JAR mithilfe des Buildscript {} -Blocks zum Build-Klassenpfad hinzufügen .

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' }

Jetzt müssen wir die Wrapper- Aufgabe ausführen und die Aufgabe bindet unser Projekt an den Wrapper. Neben den Gradlew- Dateien wird im Gradle- Ordner ein Wrapper- Ordner generiert, der eine JAR- und eine Eigenschaftendatei enthält.

Wenn wir zu einer neuen Version von Gradle wechseln möchten, müssen wir nur einen Eintrag in gradle-wrapper.properties ändern .

7. Fazit

In diesem Artikel haben wir uns Gradle angesehen und festgestellt, dass es gegenüber anderen vorhandenen Build-Tools flexibler ist, wenn es darum geht, Versionskonflikte zu lösen und transitive Abhängigkeiten zu verwalten.

Der Quellcode für diesen Artikel ist auf GitHub verfügbar.

Weiter » Ant vs Maven vs Gradle