Java >> Java tutorial >  >> Tag >> new

Hvad er nyt i Gradle 6.0

1. Oversigt

Gradle 6.0-udgivelsen bringer flere nye funktioner, der vil hjælpe med at gøre vores builds mere effektive og robuste. Disse funktioner omfatter forbedret afhængighedsstyring, udgivelse af modulmetadata, undgåelse af opgavekonfiguration og understøttelse af JDK 13.

I denne øvelse introducerer vi de nye funktioner, der er tilgængelige i Gradle 6.0. Vores eksempel på byggefiler vil bruge Gradles Kotlin DSL.

2. Forbedringer af afhængighedsstyring

Med hver udgivelse i de seneste år har Gradle foretaget trinvise forbedringer af, hvordan projekter håndterer afhængigheder. Disse afhængighedsforbedringer kulminerer i Gradle 6.0. Lad os gennemgå forbedringer af afhængighedsstyring, som nu er stabile.

2.1. API og implementeringsadskillelse

java-biblioteket plugin hjælper os med at skabe et genanvendeligt Java-bibliotek. Pluginnet opfordrer os til at adskille afhængigheder, der er en del af vores biblioteks offentlige API, fra afhængigheder, der er implementeringsdetaljer. Denne adskillelse gør builds mere stabile, fordi brugerne ikke ved et uheld henviser til typer, der ikke er en del af et biblioteks offentlige API.

java-biblioteket plugin og dets api og implementering konfigurationer blev introduceret i Gradle 3.4. Selvom dette plugin ikke er nyt for Gradle 6.0, er de forbedrede afhængighedsstyringsfunktioner, det giver, en del af den omfattende afhængighedsstyring realiseret i Gradle 6.0.

2.2. Rich versioner

Vores projektafhængighedsgrafer har ofte flere versioner af den samme afhængighed. Når dette sker, skal Gradle vælge, hvilken version af afhængigheden projektet i sidste ende skal bruge.

Gradle 6.0 giver os mulighed for at tilføje rig versionsinformation til vores afhængigheder. Rige versionsoplysninger hjælper Gradle med at træffe det bedst mulige valg ved løsning af afhængighedskonflikter.

Overvej for eksempel et projekt, der afhænger af Guava. Antag yderligere, at dette projekt bruger Guava version 28.1-jre, selvom vi ved, at det kun bruger Guava API'er, der har været stabile siden version 10.0.

Vi kan bruge require erklæring om at fortælle Gradle, at dette projekt kan bruge enhver version af Guava siden 10.0, og vi bruger foretrækker  erklæring om at fortælle Gradle, at den skal bruge 28.1-jre, hvis ingen andre begrænsninger forhindrer den i at gøre det. fordi erklæringen tilføjer en note, der forklarer denne omfattende versionsinformation:

implementation("com.google.guava:guava") {
    version {
        require("10.0")
        prefer("28.1-jre")
        because("Uses APIs introduced in 10.0. Tested with 28.1-jre")
    }
}

Hvordan hjælper dette med at gøre vores builds mere stabile? Antag, at dette projekt også er afhængig af en afhængighed foo der skal bruge Guava version 16.0. Byggefilen til foo projektet ville erklære denne afhængighed som:

dependencies {
    implementation("com.google.guava:guava:16.0")
}

Siden foo projektet afhænger af Guava 16.0, og vores projekt afhænger af både Guava version 28.1-jre og foo , vi har en konflikt. Gradles standardadfærd er at vælge den nyeste version. I dette tilfælde er det dog forkert at vælge den nyeste version , fordi foo skal bruge version 16.0.

Før Gradle 6.0 skulle brugerne løse konflikter på egen hånd. Fordi Gradle 6.0 giver os mulighed for at fortælle Gradle, at vores projekt kan bruge Guava-versioner så lave som 10.0, vil Gradle løse denne konflikt korrekt og vælge version 16.0.

Ud over kræver og foretrækker erklæringer, kan vi bruge strengt og afvis erklæringer. Den strengt erklæringen beskriver et afhængighedsversionsområde, som vores projekt skal bruge. afvisningen erklæringen beskriver afhængighedsversioner, der er inkompatible med vores projekt.

Hvis vores projekt var afhængig af en API, som vi ved vil blive fjernet i Guava 29, så bruger vi strengt erklæring for at forhindre Gradle i at bruge en version af Guava, der er større end 28. Ligeledes, hvis vi ved, at der er en fejl i Guava 27.0, der forårsager problemer for vores projekt, bruger vi afvis for at udelukke det:

implementation("com.google.guava:guava") {
    version {
        strictly("[10.0, 28[")
        prefer("28.1-jre")
        reject("27.0")
        because("""
            Uses APIs introduced in 10.0 but removed in 29. Tested with 28.1-jre.
            Known issues with 27.0
        """)
    }
}

2.3. Platforme

java-platformen plugin giver os mulighed for at genbruge et sæt afhængighedsbegrænsninger på tværs af projekter. En platformsforfatter erklærer et sæt tæt koblede afhængigheder, hvis versioner styres af platformen.

Projekter, der er afhængige af platformen, behøver ikke at angive versioner for nogen af ​​de afhængigheder, der styres af platformen. Maven-brugere vil finde, at dette ligner en Maven-forælder-POM's dependencyManagement funktion.

Platforme er især nyttige i multi-projekt builds. Hvert projekt i multi-projekt build kan bruge de samme eksterne afhængigheder, og vi ønsker ikke, at versionerne af disse afhængigheder skal være ude af synkronisering.

Lad os skabe en ny platform for at sikre, at vores multi-projekt build bruger den samme version af Apache HTTP Client på tværs af projekter. Først opretter vi et projekt, httpclient-platform, der bruger java-platformen plugin:

plugins {
    `java-platform`
}

Dernæst erklærer vi begrænsninger for afhængighederne inkluderet i denne platform. I dette eksempel vælger vi de versioner af Apache HTTP-komponenterne, som vi vil bruge i vores projekt:

dependencies {
    constraints {
        api("org.apache.httpcomponents:fluent-hc:4.5.10")
        api("org.apache.httpcomponents:httpclient:4.5.10")
    }
}

Lad os endelig tilføje en person-rest-klient projekt, der bruger Apache HTTP Client Fluent API. Her tilføjer vi en afhængighed af vores httpclient-platform projekt ved hjælp af platformen metode. Vi tilføjer også en afhængighed af org.apache.httpcomponents:fluent-hc . Denne afhængighed inkluderer ikke en version, fordi httpclient-platformen bestemmer den version, der skal bruges:

plugins {
    `java-library`
}

dependencies {
    api(platform(project(":httpclient-platform")))
    implementation("org.apache.httpcomponents:fluent-hc")
}

Java-platformen plugin hjælper med at undgå uvelkomne overraskelser under kørsel på grund af forkert tilpassede afhængigheder i build.

2.4. Testarmaturer

Før Gradle 6.0 udtog byggeforfattere, der ønskede at dele testarmaturer på tværs af projekter, disse armaturer til et andet biblioteksprojekt. Nu kan byggeforfattere udgive testarmaturer fra deres projekt ved hjælp af java-test-fixtures plugin.

Lad os bygge et bibliotek, der definerer en abstraktion og udgiver testarmaturer, der bekræfter den kontrakt, der forventes af denne abstraktion.

I dette eksempel er vores abstraktion en Fibonacci-sekvensgenerator, og testarmaturen er en JUnit 5-testmix-in. Implementatorer af Fibonacci-sekvensgeneratoren kan bruge testblandingen til at bekræfte, at de har implementeret sekvensgeneratoren korrekt.

Lad os først oprette et nyt projekt, fibonacci-spi , til vores abstraktions- og testarmaturer. Dette projekt kræver java-biblioteket og java-test-fixtures plugins:

plugins {
    `java-library`
    `java-test-fixtures`
}

Lad os derefter tilføje JUnit 5-afhængigheder til vores testarmaturer. Ligesom java-biblioteket plugin definerer api og implementering konfigurationer, java-test-fixtures plugin definerer testFixturesApi og testFixturesImplementation konfigurationer:

dependencies {
    testFixturesApi("org.junit.jupiter:junit-jupiter-api:5.8.1")
    testFixturesImplementation("org.junit.jupiter:junit-jupiter-engine:5.8.1")
}

Med vores afhængigheder på plads, lad os tilføje et JUnit 5-testmix-in til src/testFixtures/java kildesæt oprettet af java-test-fixtures plugin. Dette testmix-in bekræfter kontrakten for vores FibonacciSequenceGenerator abstraktion:

public interface FibonacciSequenceGeneratorFixture {

    FibonacciSequenceGenerator provide();

    @Test
    default void whenSequenceIndexIsNegative_thenThrows() {
        FibonacciSequenceGenerator generator = provide();
        assertThrows(IllegalArgumentException.class, () -> generator.generate(-1));
    }

    @Test
    default void whenGivenIndex_thenGeneratesFibonacciNumber() {
        FibonacciSequenceGenerator generator = provide();
        int[] sequence = { 0, 1, 1, 2, 3, 5, 8 };
        for (int i = 0; i < sequence.length; i++) {
            assertEquals(sequence[i], generator.generate(i));
        }
    }
}

Dette er alt, hvad vi skal gøre for at dele denne testopstilling med andre projekter .

Lad os nu oprette et nyt projekt, fibonacci-rekursivt , som vil genbruge dette testarmatur. Dette projekt vil erklære en afhængighed af testarmaturerne fra vores fibonacci-spi projekt ved hjælp af testFixtures metode i vores afhængigheder blokere:

dependencies {
    api(project(":fibonacci-spi"))
    
    testImplementation(testFixtures(project(":fibonacci-spi")))
    testImplementation("org.junit.jupiter:junit-jupiter-api:5.8.1")
    testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.8.1")
}

Endelig kan vi nu bruge testblandingen defineret i fibonacci-spi projekt for at skabe en ny test for vores rekursive fibonacci-sekvensgenerator:

class RecursiveFibonacciUnitTest implements FibonacciSequenceGeneratorFixture {
    @Override
    public FibonacciSequenceGenerator provide() {
        return new RecursiveFibonacci();
    }
}

Gradle 6.0 java-test-fixtures plugin giver byggeforfattere mere fleksibilitet til at dele deres testarmaturer på tværs af projekter .

3. Gradle Module Metadata Publishing

Traditionelt udgiver Gradle-projekter byggeartefakter til Ivy- eller Maven-lagre. Dette inkluderer generering af henholdsvis ivy.xml eller pom.xml metadatafiler.

Modellerne ivy.xml og pom.xml kan ikke gemme de rige afhængighedsoplysninger, som vi har diskuteret i denne artikel. Det betyder, at downstream-projekter ikke drager fordel af denne rige afhængighedsinformation, når vi udgiver vores bibliotek til et Maven- eller Ivy-lager .

Gradle 6.0 løser dette hul ved at introducere Gradle Module Metadata specifikation. Gradle Module Metadata-specifikation er et JSON-format, der understøtter lagring af alle de forbedrede modulafhængighedsmetadata introduceret i Gradle 6.0.

Projekter kan bygge og udgive denne metadatafil til Ivy- og Maven-lagre ud over traditionelle ivy.xml- og pom.xml-metadatafiler. Denne bagudkompatibilitet gør det muligt for Gradle 6.0-projekter at drage fordel af dette moduls metadata, hvis det er til stede uden at bryde ældre værktøjer.

For at udgive Gradle Module Metadata-filer skal projekter bruge det nye Maven Publish Plugin eller Ivy Publish Plugin. Fra Gradle 6.0 udgiver disse plugins Gradle Module Metadata-filen som standard. Disse plugins erstatter det gamle udgivelsessystem.

3.1. Udgivelse af Gradle Module Metadata til Maven

Lad os konfigurere en build til at udgive Gradle Module Metadata til Maven. Først inkluderer vi maven-publish i vores build-fil:

plugins {
    `java-library`
    `maven-publish`
}

Dernæst konfigurerer vi en publikation. En publikation kan indeholde et vilkårligt antal artefakter. Lad os tilføje artefakten forbundet med java konfiguration:

publishing {
    publications {
        register("mavenJava", MavenPublication::class) {
            from(components["java"])
        }
    }
}

maven-publish plugin tilføjer publishToMavenLocal opgave. Lad os bruge denne opgave til at teste vores Gradle Module Metadata-publikation:

./gradlew publishToMavenLocal

Lad os derefter liste mappen for denne artefakt i vores lokale Maven-lager:

ls ~/.m2/repository/com/baeldung/gradle-6/1.0.0/
gradle-6-1.0.0.jar	gradle-6-1.0.0.module	gradle-6-1.0.0.pom

Som vi kan se i konsoloutputtet, genererer Gradle modulmetadatafilen ud over Maven POM.

4. Configuration Avoidance API

Siden version 5.1 har Gradle opfordret plugin-udviklere til at gøre brug af nye, inkuberende Configuration Avoidance API'er. Disse API'er hjælper builds med at undgå relativt langsomme opgavekonfigurationstrin, når det er muligt . Gradle kalder dette præstationsforbedring Task Configuration Avoidance. Gradle 6.0 fremmer denne inkuberende API til stabil.

Mens funktionen til undgåelse af konfiguration for det meste påvirker plugin-forfattere, skal du bygge forfattere, der opretter enhver tilpasset konfiguration , Opgave eller Ejendom i deres bygning er også påvirket. Både plugin-forfattere og build-forfattere kan nu bruge de nye dovne konfigurations-API'er til at ombryde objekter med Provideren type, så Gradle undgår at "realisere" disse objekter, indtil de er nødvendige .

Lad os tilføje en tilpasset opgave ved hjælp af dovne API'er. Først registrerer vi opgaven ved hjælp af TaskContainer.registring udvidelsesmetode. Siden registrering returnerer en TaskProvider , oprettelsen af ​​Opgaven forekomst udsættes, indtil Gradle eller build-forfatteren kalder TaskProvider.get() . Til sidst giver vi en lukning, der konfigurerer vores Opgave efter Gradle opretter det:

val copyExtraLibs by tasks.registering(Copy::class) {
    from(extralibs)
    into(extraLibsDir)
}

Gradles Task Configuration Avoidance Migration Guide hjælper plugin-forfattere og build-forfattere med at migrere til de nye API'er. De mest almindelige migreringer for byggeforfattere omfatter:

  • tasks.register i stedet for tasks.create
  • opgaver.navngivet i stedet for tasks.getByName
  • configurations.register i stedet for configurations.create
  • project.layout.buildDirectory.dir(“foo”) i stedet for File(project.buildDir, "foo")

5. JDK 13 Support

Gradle 6.0 introducerer understøttelse af byggeprojekter med JDK 13. Vi kan konfigurere vores Java build til at bruge Java 13 med den velkendte sourceCompatibility og targetCompatibility indstillinger:

sourceCompatibility = JavaVersion.VERSION_13
targetCompatibility = JavaVersion.VERSION_13

Nogle af JDK 13s mest spændende sprogfunktioner, såsom Raw String Literals, er stadig i preview-status . Lad os konfigurere opgaverne i vores Java-build for at aktivere disse forhåndsvisningsfunktioner:

tasks.compileJava {
    options.compilerArgs.add("--enable-preview")
}
tasks.test {
    jvmArgs.add("--enable-preview")
}
tasks.javadoc {
    val javadocOptions = options as CoreJavadocOptions
    javadocOptions.addStringOption("source", "13")
    javadocOptions.addBooleanOption("-enable-preview", true)
}

6. Konklusion

I denne artikel diskuterede vi nogle af de nye funktioner i Gradle 6.0.

Vi dækkede forbedret afhængighedsstyring, udgivelse af Gradle Module Metadata, Task Configuration Avoidance, og hvordan tidlige brugere kan konfigurere deres builds til at bruge Java 13 preview sprogfunktioner.

Som altid er koden til denne artikel forbi på GitHub.


Java tag