在Gradle中,implementation
和api
是声明依赖的两种方式,它们在如何暴露依赖关系方面有所不同:
-
Implementation: 当一个模块使用
implementation
声明依赖时,该依赖仅对声明它的模块可见。这意味着该依赖对于该模块的消费者是隐藏的。因此,使用implementation
可以提高构建速度,因为更改依赖项不会强制消费者重新编译。 -
API: 相反,当使用
api
声明依赖时,这个依赖同时被暴露给该模块的消费者。如果一个模块的公共API在其接口中暴露了第三方库的类或接口,那么这个依赖应该使用api
声明。这样做的缺点是,更改api
依赖将导致依赖于该模块的所有消费者都需要重新编译。
选择使用implementation
还是api
取决于你是否想将依赖项暴露给其他依赖于你的模块的模块。
我为测试创建了两个项目:
- 项目A 是一个名为“frameworks-web-gradle-plugin”的Java库项目,依赖于“org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE”。
- 项目B 通过“implementation 'com.example.frameworks.gradle:frameworks-web-gradle-plugin:0.0.1-SNAPSHOT'”依赖于项目A。
上述依赖关系层次结构看起来像这样:[project-b] -> [project-a] -> [spring-boot-gradle-plugin]
然后我测试了以下场景:
- 使项目A通过implementation依赖于“org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE”。
在项目B根目录中使用终端运行gradle dependencies命令,通过输出的截图我们可以看到“spring-boot-gradle-plugin”出现在runtimeClasspath依赖树中,但不在compileClasspath中。我认为这正是我们不能在B中使用由A中implementation方式声明的依赖spring-boot-gradle-plugin的原因,因为compileClasspath中没有spring-boot-gradle-plugin,代码不会通过编译。 - 这次修改为使项目A通过api依赖于“org.springframework.boot:spring-boot-gradle-plugin:1.5.20.RELEASE”。
再次在项目B根目录中的终端运行gradle dependencies命令。现在“spring-boot-gradle-plugin”同时出现在compileClasspath和runtimeClasspath依赖树中。
可以看到的一个显著差异,在生产者/库项目中用implementation方式声明的依赖不会出现在消费者项目的compileClasspath中,因此我们不能在消费者项目中使用相应的库。
更多参考: StackOverflow: Gradle Implementation vs API configuration