Gradle の dependencies
で指定する compile
, api
, implementation
についての勉強メモ。
compile は非推奨
Gradle 3.4 で Java Library Plugin が追加されたことで、 dependencies
で compile
を使用することは非推奨となってたらしい(runtime
, testCompile
, testRuntime
も)。
4.7 の Java Plugin の説明では、ガッツリ Deprecated
と書かれている。
(4.6 のドキュメントだと Deprecated
って書いてないけど、明確に非推奨となったのは最近?)
代わりに implementation
と api
を使用することが推奨されている。
compile と implementation の違い
compile の場合
実装
|-settings.gradle
|-build.gradle
|
|-foo/
| |-build.gradle
| `-src/main/java/foo/
| `-Foo.java
|
`-bar/
|-build.gradle
`-src/main/java/bar/
`-Bar.java
include 'foo', 'bar'
subprojects {
apply plugin: 'java'
sourceCompatibility = 10
targetCompatibility = 10
compileJava.options.encoding = 'UTF-8'
repositories {
mavenCentral()
}
}
dependencies {
compile 'org.apache.commons:commons-lang3:3.7'
}
package bar;
import org.apache.commons.lang3.RandomStringUtils;
public class Bar {
public void hello() {
System.out.println("Bar: " + RandomStringUtils.random(10, "0123456789"));
}
}
apply plugin: 'application'
mainClassName = 'foo.Foo'
dependencies {
compile project(':bar')
}
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"));
}
}
-
foo
,bar
という2つのサブプロジェクトから成る -
bar
はcommons-lang3
に依存している -
foo
はbar
プロジェクトに依存している - それぞれのプロジェクトで
commons-lang3
を利用している
実行結果
> gradle :foo:run
Bar: 3803159716
Foo: 6423224304
implementation を使った場合
実装
dependencies {
implementation 'org.apache.commons:commons-lang3:3.7'
}
apply plugin: 'application'
mainClassName = 'foo.Foo'
dependencies {
implementation project(':bar')
}
実行結果
> gradle :foo:run
...\foo\src\main\java\foo\Foo.java:4: エラー: パッケージorg.apache.commons.lang3は存在しません
import org.apache.commons.lang3.RandomStringUtils;
^
...\foo\src\main\java\foo\Foo.java:10: エラー: シンボルを見つけられません
System.out.println("Foo: " + RandomStringUtils.random(10, "0123456789"));
^
シンボル: 変数 RandomStringUtils
場所: クラス Foo
エラー2個
...
説明
# 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 ---------------+
-
compile
で指定した依存関係は伝播する-
bar
プロジェクトでcommons-lang3
をcompile
で指定した場合、foo
プロジェクトでbar
プロジェクトを依存関係に指定すると、foo
プロジェクトはcommons-lang3
にも依存するようになる
-
-
implementation
で指定した依存関係は伝播しない-
bar
プロジェクトでcommons-lang3
をimplementation
で指定した場合、foo
プロジェクトでbar
プロジェクトを依存関係に指定しても、foo
プロジェクトはcommons-lang3
に依存しない(foo
プロジェクトはcommons-lang3
を使用できない)
-
依存関係を伝播させる
実装
apply plugin: 'java-library'
dependencies {
api 'org.apache.commons:commons-lang3:3.7'
}
実行結果
$ gradle :foo:run
Bar: 7783742303
Foo: 6741510207
説明
apply plugin: 'java-library'
dependencies {
api 'org.apache.commons:commons-lang3:3.7'
}
-
compile
のように依存関係を伝播させるには、api
で依存関係を指定する-
api
は Java Library Plugin を追加することで利用できるようになる - Java Library Plugin を使うには、
java-library
でプラグインを追加する
-
メリット
公式ドキュメントでは、 compile
ではなく implementation
を使うことについて、次のようなメリットがあると説明している。
- コンパイル時に依存関係が利用側のどこにも漏れることがない。
従って、意図しない推移的な依存関係が発生することがない。 - 取り除かれたクラスパスによってコンパイルがより早くなる。
-
implementation
で指定した依存対象が変更されても、利用する側はリコンパイルの必要がない。 - 新しい Maven プラグインと合わせて使うと、コンパイル時に必要になるライブラリと実行時に必要になるライブラリを明確に分けた POM ファイルを生成するようになり、綺麗な公開ができる(正直、 Maven プラグイン使ってないのでよくわかってない)
要するに、 compile
を使うと次のような問題があった。
- 依存関係が全て推移的に伝播していくため、依存関係が不必要に拡大してしまっていた
- 内部 API のような外部に漏らしたくない依存関係まで広がっていた
これを implementation
で定義することで、依存関係の不必要な拡大を防ぎ、本当に必要な依存関係だけを api
で推移させられるようになる。
また、 implementation
が依存関係を伝播させなくなることで、リコンパイルの頻度も減らせられるようになるメリットがある。
implementation
と api
の使い分け
以下は個人的な見解。
- 基本は
implementation
で宣言する - どうしても利用側に伝播させないといけない場合だけ
api
で利用側に公開する- 可能なら自作 API でラップすることで、使用しているライブラリへの直接の依存を無くせれたらベストだと思う
- ライブラリの差し替えが容易になる
- 自作 API で利用方法を制限することで、意図しない使われ方・間違った利用方法を減らせられる
- ただ、自作 API でのラップが大変で費用対効果が薄いなら
api
で公開するのもありかと思う
- 可能なら自作 API でラップすることで、使用しているライブラリへの直接の依存を無くせれたらベストだと思う
まとめ
configuration |
依存関係の伝播 | 定義されているプラグイン |
---|---|---|
compile |
する | Java Plugin |
implementation |
しない | Java Plugin |
api |
する | Java Library Plugin |