标签:
Gradle是一种构建工具,它抛弃了基于XML的构建脚本,取而代之的是采用一种基于Groovy的内部领域特定语言。近期,Gradle获得了极大的关注,这也是我决定去研究Gradle的原因。
这篇文章是Gradle教程的第一篇,我们有两个目标:
我们开始吧,先看一下如何安装Gradle。
如果我们使用的操作系统是Windows或Linux,我们可以根据以下步骤安装Gradle: 1. 从这个页面下载二进制文件。 2. 解压Zip文件,加入环境变量(在PATH中加入GRADLE_HOME/bin目录)。
如果在安装过程中遇到问题,可以进一步查看官方的安装指南。 如果我们使用的操作系统是OS X,我们可以使用Homebrew安装Gradle,在命令提示符中输入以下命令:
1
|
brew install gradle |
我们可以验证一下Gradle是否工作正常,在命令提示符中执行命令gradle -v即可,如果Gradle工作正常,我们应该能看到以下输出结果(当然,Windows和Linux用户看到的结果会有细微差异)。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
> gradle - v ------------------------------------------------------------ Gradle 1.12 ------------------------------------------------------------ Build time : 2014-04-29 09:24:31 UTC Build number: none Revision: a831fa866d46cbee94e61a09af15f9dd95987421 Groovy: 1.8.6 Ant: Apache Ant(TM) version 1.9.3 compiled on December 23 2013 Ivy: 2.2.0 JVM: 1.8.0 (Oracle Corporation 25.0-b70) OS: Mac OS X 10.9.3 x86_64 |
下面我们来快速浏览一下Gradle构建的基本概念。
在Gradle中,有两个基本概念:项目和任务。请看以下详解:
那么,这些概念和Gradle的构建又有什么联系呢?好,每一次Gradle的构建都包含一个或多个项目。
下面这张图展示了上面所谈到的这些概念的关系。
我们能够使用以下配置文件对Gradle的构建进行配置:
你可以在这篇文章中获得更多关于Gradle构建脚本的信息。
我们继续,下面我们看一下如果使用Gradle插件为构建工作加入新功能。
Gradle的设计理念是,所有有用的特性都由Gradle插件提供,一个Gradle插件能够:
Gradle用户手册提供了一系列标准Gradle插件。
在我们为项目加入Gradle插件时,我们可以根据名称或类型来指定Gradle插件。
我们可以将下面这行代码加入到build.gradle文件中,它通过名称指定Gradle插件(这里的名称是foo):
1
|
apply plugin: ‘foo‘ |
另一方面,我们也可以通过类型指定Gradle插件,将下面这行代码加入到build.gradle文件中(这里的类型是com.bar.foo):
1
|
apply plugin: ‘com.bar.foo‘ |
你可以阅读这篇文章,掌握应用插件的更多信息。
今天就到这里,我们来总结一下我们所学的内容。
这篇教程讲授了三部分内容:
下一篇教程,我们会讨论如何使用Gradle创建一个简单的Java工程。
http://blog.jobbole.com/71999/
这篇教程的主要内容是讲解如何用Gradle编译和打包一个简单的Java项目。
该Java项目只有一个需求:我们的构建脚本必须创建一个可执行的Jar文件,换句话说,我们必须能够使用命令java -jar jarfile.jar 来运行我们的程序。我们来看一下如何满足这个需求。
我们可以使用Java插件(译注:关于Gradle插件的定义,请查看第一篇教程)来创建一个Java项目,为了做到这点,我们需要把下面这段语句加入到build.gradle文件中:
1
|
apply plugin: ‘java‘ |
就是这样,现在我们已经创建了一个Java项目。Java插件会在我们的构建中添加一些新的约定(如默认的项目结构),新的任务,和新的属性。 让我们来快速地看一下默认的项目结构。
默认的项目结构如下:
让我们创建一个简单的主类,在这个类中会打印一个“Hello world”然后System.out出来。这个HelloWorld类的源代码如下:
1
2
3
4
5
6
7
8
|
package net.petrikainulainen.gradle; public class HelloWorld { public static void main(String[] args) { System.out.println( "Hello World!" ); } } |
HelloWorld类存放在src/main/java/net/petrikainulainen/gradle目录
这很好,然而,我们还需要编译和打包我们的项目,不是吗?我们先看一下这个Java工程中的任务。
Java插件在我们的构建中加入了很多任务,我们这篇教程涉及到的任务如下:
我们还可以执行以下命令得到一个可运行任务及其描述的完整列表
1
|
gradle tasks |
这是一个很好的方式,不需要阅读构建脚本,就能对你的项目进行大致的浏览,如果我们在项目根目录下运行这个命令,我们可以看到以下输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
|
> gradle tasks :tasks ------------------------------------------------------------ All tasks runnable from root project ------------------------------------------------------------ Build tasks ----------- assemble - Assembles the outputs of this project. build - Assembles and tests this project. buildDependents - Assembles and tests this project and all projects that depend on it. buildNeeded - Assembles and tests this project and all projects it depends on. classes - Assembles classes ‘main‘ . clean - Deletes the build directory. jar - Assembles a jar archive containing the main classes. testClasses - Assembles classes ‘test‘ . Build Setup tasks ----------------- init - Initializes a new Gradle build. [incubating] wrapper - Generates Gradle wrapper files. [incubating] Documentation tasks ------------------- javadoc - Generates Javadoc API documentation for the main source code. Help tasks ---------- dependencies - Displays all dependencies declared in root project ‘first-java-project‘ . dependencyInsight - Displays the insight into a specific dependency in root project ‘first-java-project‘ . help - Displays a help message projects - Displays the sub-projects of root project ‘first-java-project‘ . properties - Displays the properties of root project ‘first-java-project‘ . tasks - Displays the tasks runnable from root project ‘first-java-project‘ . Verification tasks ------------------ check - Runs all checks. test - Runs the unit tests. Rules ----- Pattern: build<ConfigurationName>: Assembles the artifacts of a configuration. Pattern: upload<ConfigurationName>: Assembles and uploads the artifacts belonging to a configuration. Pattern: clean<TaskName>: Cleans the output files of a task. To see all tasks and more detail, run with --all. BUILD SUCCESSFUL Total time : 2.792 secs |
我们继续,下面要讲怎样打包我们的项目。
我们可以通过使用两个不同的任务来打包项目。 如果我们在命令提示符中执行命令gradle assemble,我们可以看到以下输出:
1
2
3
4
5
6
7
8
9
10
|
> gradle assemble :compileJava :processResources :classes :jar :assemble BUILD SUCCESSFUL Total time : 3.163 secs |
如果我们在命令提示符中执行命令gradle build,我们可以看到以下输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
> gradle build :compileJava :processResources :classes :jar :assemble :compileTestJava :processTestResources :testClasses : test :check :build BUILD SUCCESSFUL Total time : 3.01 secs |
这些命令的输出表明了它们的区别:
现在,我们尝试使用以下命令运行我们的程序:
1
|
java -jar first-java-project.jar |
我们可以看到以下输出:
1
2
|
> java -jar first-java.project.jar No main manifest attribute, in first-java-project.jar |
问题出在,我们没有在manifest文件中配置Jar文件的主类,让我们继续看看怎样解决这个问题。
Java插件在我们的项目中加入了一个Jar任务,每一个Jar对象都一个manifest属性,这个属性是Manifest的一个实例。
我们可以对生成的Jar文件的主类进行配置,使用Manifest接口的attributes()方法。换句话说,我们可以使用一个包含键值对的map结构指定加入到manifest文件的属性集。
我们能够通过设置Main-Class属性的值,指定我们程序的入口点。在我们对build.gradle文件进行必要的改动后,代码如下:
1
2
3
4
5
6
7
|
apply plugin: ‘java‘ jar { manifest { attributes ‘Main-Class‘ : ‘net.petrikainulainen.gradle.HelloWorld‘ } } |
(JavaSE教程提供了关于manifest文件的更多信息。) 在我们执行gradle assemble或gradle build命令生成一个新的jar文件之后,我们可以执行以下命令运行jar文件:
1
|
java -jar first-java-project.jar |
当我们运行程序时,System.out会打印出以下信息:
1
2
|
> java -jar first-java-project.jar Hello World! |
这就是我们今天所有的内容,我们看一下我们学到了什么。
我们已经通过Gradle创建了一个简单的Java项目,这篇教程教会了我们四点:
P.S. 这篇教程的示例代码可以在Github找到。
http://blog.jobbole.com/72558/
在现实生活中,要创造一个没有任何外部依赖的应用程序并非不可能,但也是极具挑战的。这也是为什么依赖管理对于每个软件项目都是至关重要的一部分。
这篇教程主要讲述如何使用Gradle管理我们项目的依赖,我们会学习配置应用仓库以及所需的依赖,我们也会理论联系实际,实现一个简单的演示程序。
让我们开始吧。
本质上说,仓库是一种存放依赖的容器,每一个项目都具备一个或多个仓库。
Gradle支持以下仓库格式:
我们来看一下,对于每一种仓库类型,我们在构建中应该如何配置。
我们可以通过URL地址或本地文件系统地址,将Ivy仓库加入到我们的构建中。
如果想通过URL地址添加一个Ivy仓库,我们可以将以下代码片段加入到build.gradle文件中:
1
2
3
4
5
|
repositories { ivy { url "http://ivy.petrikainulainen.net/repo" } } |
如果想通过本地文件系统地址添加一个Ivy仓库,我们可以将以下代码片段加入到build.gradle文件中:
1
2
3
4
5
|
repositories { ivy { url "../ivy-repo" } } |
小贴士:如果你想要获得更多关于Ivy仓库配置的信息,你可以参考以下资源:
我们继续,下面是如何在构建中加入Maven仓库。
与Ivy仓库很类似,我们可以通过URL地址或本地文件系统地址,将Maven仓库加入到我们的构建中。
如果想通过URL地址添加一个Maven仓库,我们可以将以下代码片段加入到build.gradle文件中:
1
2
3
4
5
|
repositories { maven { url "http://maven.petrikainulainen.net/repo" } } |
如果想通过本地文件系统地址添加一个Maven仓库,我们可以将以下代码片段加入到build.gradle文件中:
1
2
3
4
5
|
repositories { maven { url "../maven-repo" } } |
在加入Maven仓库时,Gradle提供了三种“别名”供我们使用,它们分别是:
如果我们想要将Central Maven 2 仓库加入到构建中,我们必须在build.gradle文件中加入以下代码片段:
1
2
3
|
repositories { mavenCentral() } |
小贴士:如果你想要获取更多关于Maven仓库配置的信息,你可以参考这篇文章:
section 50.6.4 Maven Repositories of the Gradle User Guide
我们继续,下面是如何在构建中加入Flat Directory仓库。
如果我们想要使用Flat Directory仓库,我们需要将以下代码片段加入到build.gradle文件中:
1
2
3
4
5
|
repositories { flatDir { dirs ‘lib‘ } } |
这意味着系统将在lib目录下搜索依赖,同样的,如果你愿意的话可以加入多个目录,代码片段如下:
1
2
3
4
5
|
repositories { flatDir { dirs ‘libA‘ , ‘libB‘ } } |
小贴士:如果你想要获得更多关于Flat Directory仓库配置的信息,你可以参考以下资源:
我们继续,下面要讲的是,如何使用Gradle管理项目中的依赖。
在配置完项目仓库后,我们可以声明其中的依赖,如果我们想要声明一个新的依赖,可以采用如下步骤:
让我们看一下详细步骤:
在Gradle中,依赖是按照指定名称进行分类的,这些分类被称为配置项,我们可以使用配置项声明项目的外部依赖。
Java插件指定了若干依赖配置项,其描述如下:
我们继续,下面是如何在项目中声明依赖。
最普遍的依赖称为外部依赖,这些依赖存放在外部仓库中。一个外部依赖可以由以下属性指定:
小贴士:这些属性在Maven仓库中是必须的,如果你使用其他仓库,一些属性可能是可选的。打个比方,如果你使用Flat directory仓库,你可能只需要指定名称和版本。
我们假设我们需要指定以下依赖:
我们可以将以下代码片段加入到build.gradle中,进行依赖声明:
1
2
3
|
dependencies { compile group: ‘foo‘ , name: ‘foo‘ , version: ‘0.1‘ } |
我们也可以采用一种快捷方式声明依赖:[group]:[name]:[version]。如果我们想用这种方式,我们可以将以下代码段加入到build.gradle中:
1
2
3
|
dependencies { compile ‘foo:foo:0.1‘ } |
我们也可以在同一个配置项中加入多个依赖,传统的方式如下:
1
2
3
4
5
6
|
dependencies { compile ( [group: ‘foo‘ , name: ‘foo‘ , version: ‘0.1‘ ], [group: ‘bar‘ , name: ‘bar‘ , version: ‘0.1‘ ] ) } |
如果采用快捷方式,那可以是这样:
1
2
3
|
dependencies { compile ‘foo:foo:0.1‘ , ‘bar:bar:0.1‘ } |
自然地,声明属于不同配置项的依赖也是可以的。比如说,如果我们想要声明属于compile和testCompile配置项的依赖,可以这么做:
1
2
3
4
|
dependencies { compile group: ‘foo‘ , name: ‘foo‘ , version: ‘0.1‘ testCompile group: ‘test‘ , name: ‘test‘ , version: ‘0.1‘ } |
同样的,给力的快捷方式又来了( ̄︶ ̄)
1
2
3
4
|
dependencies { compile ‘foo:foo:0.1‘ testCompile ‘test:test:0.1‘ } |
小贴士:你可以从这篇文章中获得更多关于依赖声明的信息。
我们已经学习了依赖管理的基础知识,下面我们来实现一个演示程序。
演示程序的需求是这样的:
我们来看一下怎样实现这些需求。
我们的演示程序的一个需求是构建脚本必须使用Maven central仓库,在我们使用Maven central仓库配置构建脚本后,源代码如下:
1
2
3
4
5
6
7
8
9
10
11
|
apply plugin: ‘java‘ repositories { mavenCentral() } jar { manifest { attributes ‘Main-Class‘ : ‘net.petrikainulainen.gradle.HelloWorld‘ } } |
我们再来看一下如何对我们的演示程序进行依赖声明。
在build.gradle文件中,我们声明了两个依赖:
在我们声明了这些依赖后,build.gradle文件是这样的:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
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‘ } } |
我们继续,稍微加入一些代码。
为了实现我们演示程序的需求,“我们不得不过度工程化一下”,我们会按照下列步骤创建程序:
我们按部就班的操作一下。
首先,在src/main/java/net/petrikainulainen/gradle目录下新建一个MessageService类并加以实现,代码如下:
1
2
3
4
5
6
7
8
|
package net.petrikainulainen.gradle; public class MessageService { public String getMessage() { return "Hello World!" ; } } |
其次,在src/main/test/net/petrikainulainen/gradle目录下新建一个MessageServiceTest类,编写单元测试,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
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(); } <a href= "http://www.jobbole.com/members/test/" rel= "nofollow" > @Test </a> public void getMessage_ShouldReturnMessage() { assertEquals( "Hello World!" , messageService.getMessage()); } } |
第三,在src/main/java/net/petrikainulainen/gradle目录下新建一个HelloWorld类,这是程序的主类,从MessageService对象获取信息,并使用Log4j写入日志,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
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文件如下:
1
2
3
4
5
|
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 |
这样就好了,我们看看如何执行测试。
我们可以通过以下命令执行测试。
1
|
gradle test |
当测试通过时,我们能看到如下输出:
1
2
3
4
5
6
7
8
9
10
11
12
|
> gradle test :compileJava :processResources :classes :compileTestJava :processTestResources :testClasses : test BUILD SUCCESSFUL Total time : 4.678 secs |
然而,如果测试失败,我们将看到如下输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
> 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会在相应目录创建测试报告:
HTML测试报告是一个非常有用的工具,因为它描述了测试失败的原因。比如说,如果我们的单元测试认为MessageService类中的getMessage()方法返回字符串“Hello Worl1d!”,那么HTML报告看上去就像下图一样:
我们继续,下面是如何打包和运行我们的演示程序。
我们能够可以使用以下任意一种命令打包程序:gradle assembly或gradle build,这两个命令都会在build/libs目录中创建dependency-management.jar文件。
当我们使用java -jar dependency-management.jar命令运行演示程序时,我们可以看到如下输出:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
> 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的依赖在classpath中没有找到。
解决这个问题最简单的方式是创建一个所谓的“胖”Jar文件,即把所有程序运行所需的依赖都打包到Jar文件中去。
通过查阅Gradle Cookbook中的教程,可以修改构建脚本,如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
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‘ } } |
现在,我们可以运行演示程序了(打包后),一切正常:
1
2
|
> java -jar dependency-management.jar INFO - HelloWorld - Received message: Hello World! |
这些就是今天的内容了,我们总结一下学到了什么。
这篇教程教会了我们四个方面的内容:
如果你想要玩一玩这篇教程所涉及的演示程序,你可以从GitHub那获取。
http://blog.jobbole.com/72992/
标签:
原文地址:http://www.cnblogs.com/softidea/p/4525274.html