[JAVA] Über Gradles Kompilierung, API, Implementierung usw.

Studiennotizen zu "Kompilieren", "API" und "Implementierung", angegeben durch "Abhängigkeiten" in Gradle.

Kompilieren ist veraltet

Java Library Plugin wurde in Gradle 3.4 (https://docs.gradle.org/3.4/release-notes) hinzugefügt. (html # the-java-library-plugin) scheint die Verwendung von "compile" mit "dependencies" veraltet zu sein (auch "runtime", "testCompile", "testRuntime").

In 4.7 Beschreibung des Java-Plugins wird es als "Veraltet" geschrieben. (4.6 Dokumentation sagt nicht "Veraltet", aber es ist definitiv veraltet Vor kurzem?)

Es wird empfohlen, stattdessen "Implementierung" und "API" zu verwenden.

Unterschied zwischen Kompilieren und Implementieren

Zum Kompilieren

Implementierung

Projektstruktur


|-settings.gradle
|-build.gradle
|
|-foo/
|  |-build.gradle
|  `-src/main/java/foo/
|    `-Foo.java
|
`-bar/
   |-build.gradle
   `-src/main/java/bar/
     `-Bar.java

/settings.gradle


include 'foo', 'bar'

/build.gradle


subprojects {
    apply plugin: 'java'

    sourceCompatibility = 10
    targetCompatibility = 10

    compileJava.options.encoding = 'UTF-8'

    repositories {
        mavenCentral()
    }
}

/bar/build.gradle


dependencies {
    compile 'org.apache.commons:commons-lang3:3.7'
}

Bar.java


package bar;

import org.apache.commons.lang3.RandomStringUtils;

public class Bar {

    public void hello() {
        System.out.println("Bar: " + RandomStringUtils.random(10, "0123456789"));
    }
}

/foo/build.gradle


apply plugin: 'application'

mainClassName = 'foo.Foo'

dependencies {
    compile project(':bar')
}

Foo.java


package foo;

import bar.Bar;
import org.apache.commons.lang3.RandomStringUtils;

public class Foo {

    public static void main(String... args) {
        new Bar().hello();
        System.out.println("Foo: " + RandomStringUtils.random(10, "0123456789"));
    }
}

** Ausführungsergebnis **

> gradle :foo:run
Bar: 3803159716
Foo: 6423224304

Bei Verwendung der Implementierung

Implementierung

/bar/build.gradle


dependencies {
    implementation 'org.apache.commons:commons-lang3:3.7'
}

/foo/build.gradle


apply plugin: 'application'

mainClassName = 'foo.Foo'

dependencies {
    implementation project(':bar')
}

** Ausführungsergebnis **

> gradle :foo:run

...\foo\src\main\java\foo\Foo.java:4:Error:Paket org.apache.commons.lang3 existiert nicht
import org.apache.commons.lang3.RandomStringUtils;
                               ^
...\foo\src\main\java\foo\Foo.java:10:Error:Symbol kann nicht gefunden werden
        System.out.println("Foo: " + RandomStringUtils.random(10, "0123456789"));
                                     ^
Symbol:Variable RandomStringUtils
Ort:Klasse Foo
2 Fehler

...

Erläuterung

Abhängigkeitsbeziehung


# compile
[foo] --compile--> [bar] --compile--> [commons-lang3]

  [foo] - ok -> [bar] - ok -> [commons-lang3]
    |                               ^
    |                               |
    +------------ ok ---------------+

# implementation
[foo] --implementation--> [bar] --implementation--> [commons-lang3]

  [foo] - ok -> [bar] - ok -> [commons-lang3]
    |                               x
    |                               |
    +------------ ng ---------------+

Abhängigkeiten verbreiten

Implementierung

/bar/build.gradle


apply plugin: 'java-library'

dependencies {
    api 'org.apache.commons:commons-lang3:3.7'
}

** Ausführungsergebnis **

$ gradle :foo:run

Bar: 7783742303
Foo: 6741510207

Erläuterung

/bar/build.gradle


apply plugin: 'java-library'

dependencies {
    api 'org.apache.commons:commons-lang3:3.7'
}

verdienen

In der offiziellen Dokumentation wird erläutert, dass die Verwendung von "Implementierung" anstelle von "Kompilieren" die folgenden Vorteile bietet:

  1. Abhängigkeiten werden zur Kompilierungszeit nirgendwo auf der Benutzerseite durchgesickert. Daher treten keine unbeabsichtigten Übergangsabhängigkeiten auf.
  2. Der entfernte Klassenpfad beschleunigt die Kompilierung.
  3. Auch wenn die in "Implementierung" angegebene Abhängigkeit geändert wird, muss der Benutzer nicht neu kompilieren.
  4. In Kombination mit dem neuen Maven-Plug-In wird eine POM-Datei generiert, die die zur Kompilierungszeit erforderlichen Bibliotheken und die zur Laufzeit erforderlichen Bibliotheken klar voneinander trennt und ordentlich veröffentlicht werden kann (ehrlich gesagt, Maven-Plug-In). Ich benutze es nicht, also bin ich mir nicht sicher.

Kurz gesagt, die Verwendung von "Kompilieren" hatte die folgenden Probleme.

――Da alle Abhängigkeiten vorübergehend weitergegeben werden, haben sich die Abhängigkeiten unnötig erweitert.

Durch die Definition mit "Implementierung" ist es möglich, eine unnötige Erweiterung von Abhängigkeiten zu verhindern und nur die Abhängigkeiten zu überführen, die mit "API" wirklich notwendig sind.

Es hat auch den Vorteil, dass die Häufigkeit von Neukompilierungen reduziert werden kann, indem verhindert wird, dass "Implementierung" Abhängigkeiten verbreitet.

Ordnungsgemäße Verwendung von "Implementierung" und "API"

Das Folgende ist meine persönliche Meinung.

Zusammenfassung

configuration Abhängigkeitsausbreitung Definiertes Plug-In
compile Machen Java Plugin
implementation TU es nicht Java Plugin
api Machen Java Library Plugin

Referenz

Recommended Posts

Über Gradles Kompilierung, API, Implementierung usw.
Kauen Sie über API
Informationen zur Apache Inference API
Informationen zur Implementierung der Zusammenführungsverarbeitung einschließlich der Sortierfunktion der Stream-API
Informationen zur Apache Jena Ontology API