Gradle入门:依赖管理
即使不是没有可能,创建没有任何外部依赖关系的现实应用程序也是一项挑战。 这就是为什么依赖性管理是每个软件项目中至关重要的部分的原因。
这篇博客文章描述了我们如何使用Gradle管理项目的依赖关系。 我们将学习配置已使用的存储库和所需的依赖项。 我们还将通过实现一个简单的示例应用程序将此理论应用于实践。
让我们开始吧。
补充阅读:
- Gradle入门:简介可帮助您安装Gradle,描述Gradle构建的基本概念,并描述如何使用Gradle插件向构建中添加功能。
- Gradle入门:我们的第一个Java项目描述了如何使用Gradle创建Java项目并将应用程序打包到可执行jar文件中。
储存库管理简介
存储库本质上是依赖项容器,每个项目可以使用零个或多个存储库。
Gradle支持以下存储库格式:
让我们了解如何在构建中配置每种存储库类型。
将常春藤存储库添加到我们的构建中
我们可以使用它的url地址或它在本地文件系统中的位置将Ivy存储库添加到我们的构建中。
如果要使用其常春藤地址添加常春藤存储库,则必须将以下代码片段添加到build.gradle文件中:
repositories { ivy { url "http://ivy.petrikainulainen.net/repo" } }
如果要使用文件系统中的位置添加常春藤存储库,则必须将以下代码段添加到build.gradle文件中:
repositories { ivy { url "../ivy-repo" } }
如果您想获得有关配置Ivy存储库的更多信息,则应检查以下资源:
让我们继续前进,找出如何将Maven存储库添加到我们的构建中。
将Maven存储库添加到我们的构建中
我们可以使用其URL地址或在本地文件系统中的位置将Maven存储库添加到我们的构建中。
如果要使用其URL添加Maven存储库,则必须将以下代码段添加到build.gradle文件中:
repositories { maven { url "http://maven.petrikainulainen.net/repo" } }
如果要通过使用文件系统中的Maven存储库来添加Maven存储库,则必须将以下代码段添加到build.gradle文件中:
repositories { maven { url "../maven-repo" } }
将Maven存储库添加到构建中时,Gradle可以使用三个“别名”。 这些别名是:
- mavenCentral()别名意味着从中央Maven 2存储库中获取依赖项。
- jcenter()别名表示从Bintray的JCenter Maven存储库中获取依赖项。
- mavenLocal()别名意味着从本地Maven存储库中获取依赖项。
如果要在构建中添加中央Maven 2存储库,则必须将以下代码段添加到build.gradle文件中:
repositories { mavenCentral() }
如果要获取有关配置Maven存储库的更多信息,则应查阅Gradle用户指南的第50.6.4节“ Maven存储库” 。
让我们继续前进,了解如何向构建中添加平面目录存储库。
将平面目录存储库添加到我们的版本中
如果要使用平面目录存储库,则必须将以下代码片段添加到build.gradle文件中:
repositories { flatDir { dirs 'lib' } }
这意味着从lib目录中搜索依赖项。 另外,如果需要,可以通过将以下代码段添加到build.gradle文件中来使用多个目录:
repositories { flatDir { dirs 'libA', 'libB' } }
如果要获取有关平面目录存储库的更多信息,则应检查以下资源:
让我们继续前进,了解如何使用Gradle管理项目的依赖关系。
依赖管理简介
配置项目的存储库后,我们可以声明其依赖项。 如果我们要声明一个新的依赖关系,我们必须执行以下步骤:
- 指定依赖项的配置。
- 声明所需的依赖项。
让我们仔细看看这些步骤。
将依赖项分组到配置中
在Gradle中,依赖项分为一组命名的依赖项。 这些组称为配置,我们使用它们来声明项目的外部依赖关系。
Java插件指定了几种依赖项配置 ,下面对此进行了描述:
- 当我们编译项目的源代码时,需要将添加到编译配置的依赖项。
- 运行时配置包含运行时所需的依赖项。 此配置包含添加到编译配置的依赖项。
- testCompile配置包含编译项目测试所需的依赖项。 此配置包含我们项目的已编译类以及添加到编译配置中的依赖项。
- testRuntime配置包含运行我们的测试时所需的依赖项。 此配置包含添加到compile , runtime和testCompile配置的依赖项。
- 档案配置包含由我们的项目产生的工件(例如Jar文件)。
- 默认配置组包含运行时所需的依赖项。
让我们继续前进,找出如何声明Gradle项目的依赖项。
声明项目的依存关系
最常见的依赖项称为外部依赖项,可从外部存储库找到。 通过使用以下属性来标识外部依赖项:
- group属性标识依赖项的组(Maven用户将此属性称为groupId )。
- name属性标识依赖项的名称(Maven用户将此属性称为artifactId )。
- version属性指定外部依赖项的版本(Maven用户将此属性称为version )。
使用Maven存储库时,这些属性是必需的。 如果使用其他存储库,则某些属性可能是可选的。
例如,如果使用平面目录存储库,则可能仅需要指定name和version 。
假设我们必须声明以下依赖关系:
- 依赖项的组为“ foo”。
- 依赖项的名称为“ foo”。
- 依赖项的版本为0.1。
- 编译我们的项目时需要依赖项。
我们可以通过将以下代码片段添加到build.gradle文件中来声明此依赖性:
dependencies { compile group: 'foo', name: 'foo', version: '0.1' }
我们还可以使用遵循以下语法的快捷方式形式声明项目的依赖项: [group]:[name]:[version] 。 如果要使用快捷方式表单,则必须将以下代码片段添加到build.gradle文件中:
dependencies { compile 'foo:foo:0.1' }
我们还可以将多个依赖项添加到同一配置中。 如果要在声明依赖项时使用“常规”语法,则必须将以下代码片段添加到build.gradle文件中:
dependencies { compile ( [group: 'foo', name: 'foo', version: '0.1'], [group: 'bar', name: 'bar', version: '0.1'] ) }
另一方面,如果我们要使用快捷方式表单, build.gradle文件的相关部分如下所示:
dependencies { compile 'foo:foo:0.1', 'bar:bar:0.1' }
自然可以声明属于不同配置的依赖项。 例如,如果我们要声明属于compile和testCompile配置的依赖项,则必须将以下代码片段添加到build.gradle文件中:
dependencies { compile group: 'foo', name: 'foo', version: '0.1' testCompile group: 'test', name: 'test', version: '0.1' }
同样,可以使用快捷方式表格。 如果要使用快捷方式表单声明相同的依赖项,则build.gradle文件的相关部分如下所示:
dependencies { compile 'foo:foo:0.1' testCompile 'test:test:0.1' }
阅读第50.4节“如何声明Gradle用户指南”中的依赖项,可以获得有关声明依赖项的更多信息。
现在,我们已经学习了依赖管理的基础知识。 让我们继续并实现示例应用程序。
创建示例应用程序
我们的示例应用程序的要求在以下内容中进行了描述:
- 示例应用程序的构建脚本必须使用Maven中央存储库。
- 示例应用程序必须使用Log4j将接收到的消息写入日志。
- 示例应用程序必须包含单元测试,以确保返回正确的消息。 这些单元测试必须使用JUnit编写。
- 我们的构建脚本必须创建一个可执行的jar文件。
让我们找出如何满足这些要求。
配置我们的版本库
示例应用程序的要求之一是其构建脚本必须使用Maven中央存储库。 在配置好构建脚本以使用Maven中央存储库之后,其源代码如下所示(相关部分已突出显示):
apply plugin: 'java' repositories { mavenCentral() } jar { manifest { attributes 'Main-Class': 'net.petrikainulainen.gradle.HelloWorld' } }
让我们继续并声明示例应用程序的依赖项。
声明示例应用程序的依赖关系
我们必须在build.gradle文件中声明两个依赖项 :
- Log4j(版本1.2.17)用于将接收到的消息写入日志。
- JUnit(版本4.11)用于为示例应用程序编写单元测试。
声明这些依赖关系后, build.gradle文件如下所示(相关部分突出显示):
apply plugin: 'java' repositories { mavenCentral() } dependencies { compile 'log4j:log4j:1.2.17' testCompile 'junit:junit:4.11' } jar { manifest { attributes 'Main-Class': 'net.petrikainulainen.gradle.HelloWorld' } }
让我们继续写一些代码。
编写代码
为了满足示例应用程序的要求,“我们必须对其进行过度设计”。 我们可以按照以下步骤创建示例应用程序:
- 创建一个MessageService类,该类返回字符串“ Hello World!”。 调用其getMessage()方法时。
- 创建这确保了MessageServiceTest类的MessageService类返回字符串“世界,你好!”的getMessage()方法。
- 创建我们的应用程序的主类,该类从MessageService对象获取消息,并使用Log4j将消息写入日志。
- 配置Log4j。
让我们一步一步地完成这些步骤。
首先 ,我们必须在src / main / java / net / petrikainulainen / gradle目录中创建一个MessageService类并实现它。 完成此操作后,其源代码如下所示:
package net.petrikainulainen.gradle; public class MessageService { public String getMessage() { return "Hello World!"; } }
其次 ,我们在src / main / test / net / petrikainulainen / gradle目录中创建了一个MessageServiceTest ,并将单元测试写入了MessageService类的getMessage()方法。 MessageServiceTest类的源代码如下所示:
package net.petrikainulainen.gradle; import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; public class MessageServiceTest { private MessageService messageService; @Before public void setUp() { messageService = new MessageService(); } @Test public void getMessage_ShouldReturnMessage() { assertEquals("Hello World!", messageService.getMessage()); } }
第三 ,我们在src / main / java / net / petrikainulainen / gradle目录中创建了一个HelloWorld类。 此类是我们应用程序的主要类别。 它从MessageService对象获取消息,然后使用Log4j将其写入日志。 HelloWorld类的源代码如下所示:
package net.petrikainulainen.gradle; import org.apache.log4j.Logger; public class HelloWorld { private static final Logger LOGGER = Logger.getLogger(HelloWorld.class); public static void main(String[] args) { MessageService messageService = new MessageService(); String message = messageService.getMessage(); LOGGER.info("Received message: " + message); } }
第四 ,我们必须使用从src / main / resources目录中找到的log4j.properties来配置Log4j。 log4j.properties文件如下所示:
log4j.appender.Stdout=org.apache.log4j.ConsoleAppender log4j.appender.Stdout.layout=org.apache.log4j.PatternLayout log4j.appender.Stdout.layout.conversionPattern=%-5p - %-26.26c{1} - %m\n log4j.rootLogger=DEBUG,Stdout
这就对了。 让我们找出如何运行示例应用程序的测试。
运行单元测试
我们可以使用以下命令运行单元测试:
gradle test
测试通过后,我们将看到以下输出:
> gradle test :compileJava :processResources :classes :compileTestJava :processTestResources :testClasses :test BUILD SUCCESSFUL Total time: 4.678 secs
但是,如果我们的单元测试失败,则会看到以下输出(突出显示了有趣的部分):
> gradle test :compileJava :processResources :classes :compileTestJava :processTestResources :testClasses :test net.petrikainulainen.gradle.MessageServiceTest > getMessage_ShouldReturnMessageFAILED org.junit.ComparisonFailure at MessageServiceTest.java:22 1 test completed, 1 failed :test FAILED FAILURE: Build failed with an exception. * What went wrong: Execution failed for task ':test'. > There were failing tests. See the report at: file:///Users/loke/Projects/Java/Blog/gradle-examples/dependency-management/build/reports/tests/index.html * Try: Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. BUILD FAILED Total time: 4.461 secs
如我们所见,如果我们的单元测试失败,则描述:
- 哪些测试失败。
- 运行了多少测试以及失败了多少测试。
- 测试报告的位置,该报告提供有关失败(和通过)测试的其他信息。
当我们运行单元测试时,Gradle将测试报告创建到以下目录:
- build / test-results目录包含每个测试运行的原始数据。
- build / reports / tests目录包含一个HTML报告,该报告描述了我们的测试结果。
HTML测试报告是非常有用的工具,因为它描述了测试失败的原因 。 例如,如果我们的单元测试期望MessageService类的getMessage()方法返回字符串“ Hello Worl1d!”,则该测试用例HTML测试报告将如下所示:
让我们继续前进,了解如何打包和运行示例应用程序。
打包并运行我们的示例应用程序
我们可以使用以下命令之一打包应用程序:em> gradle assembly或gradle build 。 这两个命令都会在build / libs目录中创建dependency-management.jar文件。
通过使用命令java -jardependency-management.jar运行示例应用程序时,我们看到以下输出:
> java -jar dependency-management.jar Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/log4j/Logger at net.petrikainulainen.gradle.HelloWorld.<clinit>(HelloWorld.java:10) Caused by: java.lang.ClassNotFoundException: org.apache.log4j.Logger at java.net.URLClassLoader$1.run(URLClassLoader.java:372) at java.net.URLClassLoader$1.run(URLClassLoader.java:361) at java.security.AccessController.doPrivileged(Native Method) at java.net.URLClassLoader.findClass(URLClassLoader.java:360) at java.lang.ClassLoader.loadClass(ClassLoader.java:424) at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308) at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ... 1 more
发生此异常的原因是,当我们运行应用程序时,没有从类路径中找到Log4j依赖项。
解决此问题的最简单方法是创建一个所谓的“胖” jar文件。 这意味着我们会将所需的依赖项打包到创建的jar文件中。
在按照Gradle Cookbook中的说明进行操作之后,我们的构建脚本如下所示(相关部分已突出显示):
apply plugin: 'java' repositories { mavenCentral() } dependencies { compile 'log4j:log4j:1.2.17' testCompile 'junit:junit:4.11' } jar { from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } } manifest { attributes 'Main-Class': 'net.petrikainulainen.gradle.HelloWorld' } }
现在,我们可以运行示例应用程序(打包后),如我们所见,一切都正常运行:
> java -jar dependency-management.jar INFO - HelloWorld - Received message: Hello World!
今天就这些。 让我们总结一下我们从此博客文章中学到的知识。
摘要
这篇博客文章教会了我们四件事:
- 我们学习了如何配置构建所使用的存储库。
- 我们学习了如何声明所需的依赖关系并将这些依赖关系分组为配置。
- 我们了解到,Gradle在运行测试时会创建一个HTML测试报告。
- 我们了解了如何创建一个所谓的“胖” jar文件。
如果您想玩这个博客文章的示例应用程序,可以从Github获得它 。
翻译自: https://www.javacodegeeks.com/2014/07/getting-started-with-gradle-dependency-management.html