Gradle是一种构建工具,它抛弃了基于XML的构建脚本,取而代之的是采用一种基于Groovy的内部领域特定语言。近期,Gradle获得了极大的关注,这也是我决定去研究Gradle的原因。

这篇文章是Gradle教程的第一篇,我们有两个目标:

  • 1. 帮助我们学会安装Gradle。
  • 2. 介绍一些基本概念,这有助于我们进一步理解本教程的后面章节。

我们开始吧,先看一下如何安装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中,有两个基本概念:项目任务。请看以下详解:

  • 项目是指我们的构建产物(比如Jar包)或实施产物(将应用程序部署到生产环境)。一个项目包含一个或多个任务。
  • 任务是指不可分的最小工作单元,执行构建工作(比如编译项目或执行测试)。

那么,这些概念和Gradle的构建又有什么联系呢?好,每一次Gradle的构建都包含一个或多个项目

下面这张图展示了上面所谈到的这些概念的关系。

我们能够使用以下配置文件对Gradle的构建进行配置:

  • Gradle构建脚本(build.gradle)指定了一个项目和它的任务。
  • Gradle属性文件(gradle.properties)用来配置构建属性。
  • Gradle设置文件(gradle.settings)对于只有一个项目的构建而言是可选的,如果我们的构建中包含多于一个项目,那么它就是必须的,因为它描述了哪一个项目参与构建。每一个多项目的构建都必须在项目结构的根目录中加入一个设置文件。

你可以在这篇文章中获得更多关于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
  • 我们理解了Gradle构建的一些基本知识
  • 我们了解了如何使用Gradle插件为我们的构建工作增加功能。

下一篇教程,我们会讨论如何使用Gradle创建一个简单的Java工程。
http://blog.jobbole.com/71999/

这篇教程的主要内容是讲解如何用Gradle编译和打包一个简单的Java项目。

该Java项目只有一个需求:我们的构建脚本必须创建一个可执行的Jar文件,换句话说,我们必须能够使用命令java -jar jarfile.jar 来运行我们的程序。我们来看一下如何满足这个需求。

创建一个Java项目

我们可以使用Java插件(译注:关于Gradle插件的定义,请查看第一篇教程)来创建一个Java项目,为了做到这点,我们需要把下面这段语句加入到build.gradle文件中:

1
apply plugin: 'java'

就是这样,现在我们已经创建了一个Java项目。Java插件会在我们的构建中添加一些新的约定(如默认的项目结构),新的任务,和新的属性。 让我们来快速地看一下默认的项目结构。

Java项目结构

默认的项目结构如下:

  • src/main/java目录包含了项目的源代码。
  • src/main/resources目录包含了项目的资源(如属性文件)。
  • src/test/java目录包含了测试类。
  • src/test/resources目录包含了测试资源。所有我们构建生成的文件都会在build目录下被创建,这个目录涵盖了以下的子目录,这些子目录我们会在这篇教程中提到,另外还有一些子目录我们会放在以后讲解。
  • classes目录包含编译过的.class文件。
  • libs目录包含构建生成的jarwar文件。

为构建加入一个主类(main class)

让我们创建一个简单的主类,在这个类中会打印一个“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工程中的任务

Java插件在我们的构建中加入了很多任务,我们这篇教程涉及到的任务如下:

  • assemble任务会编译程序中的源代码,并打包生成Jar文件,这个任务不执行单元测试。
  • build任务会执行一个完整的项目构建。
  • clean任务会删除构建目录。
  • compileJava任务会编译程序中的源代码。

我们还可以执行以下命令得到一个可运行任务及其描述的完整列表

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

这些命令的输出表明了它们的区别:

  • assemble任务仅仅执行项目打包所必须的任务集。
  • build任务执行项目打包所必须的任务集,以及执行自动化测试。这两个命令都会在build/libs目录中创建一个file-java-project.jar文件。默认创建的Jar文件名称是由这个模版决定的:[projectname].jar,此外,项目的默认名称和其所处的目录名称是一致的。因此如果你的项目目录名称是first-java-project,那么创建的Jar文件名称就是first-java-project.jar。

现在,我们尝试使用以下命令运行我们的程序:

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文件的主类,让我们继续看看怎样解决这个问题。

配置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 assemblegradle build命令生成一个新的jar文件之后,我们可以执行以下命令运行jar文件:

1
java -jar first-java-project.jar

当我们运行程序时,System.out会打印出以下信息:

1
2
> java -jar first-java-project.jar
Hello World!

这就是我们今天所有的内容,我们看一下我们学到了什么。

总结

我们已经通过Gradle创建了一个简单的Java项目,这篇教程教会了我们四点:

  • 我们了解了可以使用Gradle的Java插件创建一个Java项目。
  • 我们知道了Java项目的默认结构和Maven项目的默认结构是一样的。
  • 我们知道了构建所生成的所有文件都能在build目录下找到。
  • 我们知道了我们可以自定义加入到manifest文件中的属性。

P.S. 这篇教程的示例代码可以在Github找到。
http://blog.jobbole.com/72558/

在现实生活中,要创造一个没有任何外部依赖的应用程序并非不可能,但也是极具挑战的。这也是为什么依赖管理对于每个软件项目都是至关重要的一部分。

这篇教程主要讲述如何使用Gradle管理我们项目的依赖,我们会学习配置应用仓库以及所需的依赖,我们也会理论联系实际,实现一个简单的演示程序。

让我们开始吧。

仓库管理简介

本质上说,仓库是一种存放依赖的容器,每一个项目都具备一个或多个仓库。

Gradle支持以下仓库格式:

我们来看一下,对于每一种仓库类型,我们在构建中应该如何配置。

在构建中加入Ivy仓库

我们可以通过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仓库。

在构建中加入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提供了三种“别名”供我们使用,它们分别是:

  • mavenCentral()别名,表示依赖是从Central Maven 2 仓库中获取的。
  • jcenter()别名,表示依赖是从Bintary’s JCenter Maven 仓库中获取的。
  • mavenLocal()别名,表示依赖是从本地的Maven仓库中获取的。

如果我们想要将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仓库

如果我们想要使用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管理项目中的依赖。

依赖管理简介

在配置完项目仓库后,我们可以声明其中的依赖,如果我们想要声明一个新的依赖,可以采用如下步骤:

  1. 指定依赖的配置。
  2. 声明所需的依赖。

让我们看一下详细步骤:

配置中的依赖分类

在Gradle中,依赖是按照指定名称进行分类的,这些分类被称为配置项,我们可以使用配置项声明项目的外部依赖。

Java插件指定了若干依赖配置项,其描述如下:

  • 当项目的源代码被编译时,compile配置项中的依赖是必须的。
  • runtime配置项中包含的依赖在运行时是必须的。
  • testCompile配置项中包含的依赖在编译项目的测试代码时是必须的。
  • testRuntime配置项中包含的依赖在运行测试代码时是必须的。
  • archives配置项中包含项目生成的文件(如Jar文件)。
  • default配置项中包含运行时必须的依赖。

我们继续,下面是如何在项目中声明依赖。

声明项目依赖

最普遍的依赖称为外部依赖,这些依赖存放在外部仓库中。一个外部依赖可以由以下属性指定:

  • group属性指定依赖的分组(在Maven中,就是groupId)。
  • name属性指定依赖的名称(在Maven中,就是artifactId)。
  • version属性指定外部依赖的版本(在Maven中,就是version)。

小贴士:这些属性在Maven仓库中是必须的,如果你使用其他仓库,一些属性可能是可选的。打个比方,如果你使用Flat directory仓库,你可能只需要指定名称和版本

我们假设我们需要指定以下依赖:

  • 依赖的分组是foo
  • 依赖的名称是foo
  • 依赖的版本是0.1
  • 在项目编译时需要这些依赖。

我们可以将以下代码片段加入到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'
}

自然地,声明属于不同配置项的依赖也是可以的。比如说,如果我们想要声明属于compiletestCompile配置项的依赖,可以这么做:

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仓库。
  • 演示程序必须使用Log4j写入日志。
  • 演示程序必须包含包含单元测试,保证正确的信息返回,单元测试必须使用JUnit编写。
  • 演示程序必须创建一个可执行的Jar文件。

我们来看一下怎样实现这些需求。

配置仓库

我们的演示程序的一个需求是构建脚本必须使用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'
    }
}

我们继续,稍微加入一些代码。

编写代码

为了实现我们演示程序的需求,“我们不得不过度工程化一下”,我们会按照下列步骤创建程序:

  1. 创建一个MessageService类,当其中的getMessage()方法被调用时,返回字符串“Hello World!”。
  2. 创建一个MessageServiceTest类,确保MessageService类中的getMessage()方法返回字符串“Hello World!”。
  3. 创建程序的主类,从MessageService对象获取信息,并使用Log4j写入日志。
  4. 配置Log4j。

我们按部就班的操作一下。

首先,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会在相应目录创建测试报告:

  • build/test-results目录包含每次测试执行的原始数据。
  • build/reports/tests目录包含一个HTML报告,描述了测试的结果。

HTML测试报告是一个非常有用的工具,因为它描述了测试失败的原因。比如说,如果我们的单元测试认为MessageService类中的getMessage()方法返回字符串“Hello Worl1d!”,那么HTML报告看上去就像下图一样:

我们继续,下面是如何打包和运行我们的演示程序。

打包和运行程序

我们能够可以使用以下任意一种命令打包程序:gradle assemblygradle 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!

这些就是今天的内容了,我们总结一下学到了什么。

总结

这篇教程教会了我们四个方面的内容:

  • 我们学会了配置构建所需的仓库。
  • 我们学会了如何声明所需的依赖以及依赖的分类(分组)。
  • 我们了解了Gradle会在测试执行后创建一个HTML测试报告。
  • 我们学会了创建一个所谓的“胖”Jar文件。

如果你想要玩一玩这篇教程所涉及的演示程序,你可以从GitHub那获取。
http://blog.jobbole.com/72992/

Gradle入门系列(转)的更多相关文章

  1. 【系列教程1】Gradle入门系列三:依赖管理

    在现实生活中,要创造一个没有任何外部依赖的应用程序并非不可能,但也是极具挑战的.这也是为什么依赖管理对于每个软件项目都是至关重要的一部分. 这篇教程主要讲述如何使用Gradle管理我们项目的依赖,我们 ...

  2. 【系列教程1】Gradle入门系列二:第一个Java项目

    这篇教程的主要内容是讲解如何用Gradle编译和打包一个简单的Java项目. 该Java项目只有一个需求:我们的构建脚本必须创建一个可执行的Jar文件,换句话说,我们必须能够使用命令java -jar ...

  3. 【系列教程1】Gradle入门系列一:简介

    Gradle是一种构建工具,它抛弃了基于XML的构建脚本,取而代之的是采用一种基于Groovy的内部领域特定语言.近期,Gradle获得了极大的关注. 这篇文章是Gradle教程的第一篇,我们有两个目 ...

  4. Gradle入门系列

    http://blog.jobbole.com/71999/ 版权声明:本文为博主原创文章,未经博主允许不得转载.

  5. Gradle学习系列之二——创建Task的多种方法

    在本系列的上篇文章中,我们讲到了Gradle入门,在本篇文章中我们将讲到创建Task的多种方法. 请通过以下方式下载本系列文章的Github示例代码: git clone https://github ...

  6. Grails入门系列(一)

    Grails入门系列(一) JAVAweb开发技术相对于php,python,note.js等新式技术更为复杂,向来以繁杂的配置著称,但是Java任然被广泛的应用于大型企业级的项目,主要是因为技术成熟 ...

  7. Angular2入门系列教程7-HTTP(一)-使用Angular2自带的http进行网络请求

    上一篇:Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数 感觉这篇不是很好写,因为涉及到网络请求,如果采用真实的网络请求,这个例子大家拿到手估计还要自己写一个web ...

  8. ABP入门系列(1)——学习Abp框架之实操演练

    作为.Net工地搬砖长工一名,一直致力于挖坑(Bug)填坑(Debug),但技术却不见长进.也曾热情于新技术的学习,憧憬过成为技术大拿.从前端到后端,从bootstrap到javascript,从py ...

  9. Angular2入门系列教程6-路由(二)-使用多层级路由并在在路由中传递复杂参数

    上一篇:Angular2入门系列教程5-路由(一)-使用简单的路由并在在路由中传递参数 之前介绍了简单的路由以及传参,这篇文章我们将要学习复杂一些的路由以及传递其他附加参数.一个好的路由系统可以使我们 ...

随机推荐

  1. java--ThreadPool线程池简单用法

    package com.threadPool; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent. ...

  2. Embedded Linux Primer----嵌入式Linux基础教程--前言

    APractical,Real-WorldApproach ChristopherHallinan 计算机无处不在. 事实上,当然了,对于那些大约在过去25年期间没有生活在洞穴中的人来说没有什么惊奇的 ...

  3. HTML5:footer定位(底部+居中)的探讨+div图片居中问题

    初学HTML+CSS布局,尝试自己写一个百度首页,可是footer的定位遇到麻烦而且百度没有好的解决方法,在此记录下逐步的过程.记录之,备忘. 初学,解决方法难免出现不妥之处,也请看到这篇文章的前辈指 ...

  4. TMG 2010 VPN配置

    微软的ISA 到2006以后就叫TMG了,上周在公司的服务器上安装测试了下,虽然增加了很多功能,但是主要功能上和ISA 2004差不多,最近在部署L2TP VPN,由于防火墙带的远程访问VPN为纯的L ...

  5. 【剑指offer】旋转数组的最小值

    採用二分查找的策略,重点要考虑一些边界情况:旋转了0元素.即输入的是一个升序排列的数组.仅仅包括一个数字的数组.有非常多反复数字的数组等. AC代码: #include<stdio.h> ...

  6. Knockout应用开发指南 第四章:模板绑定

    原文:Knockout应用开发指南 第四章:模板绑定 模板绑定The template binding 目的 template绑定通过模板将数据render到页面.模板绑定对于构建嵌套结构的页面非常方 ...

  7. PHPDocumentor代码注释规范说明

       PHPDocumentor是一个的用PHP写的道具,对于有规则注释的php程序,它能够快速生成具有相互参照,索引等功能的API文档. 标记 用途 描述 @abstract   抽象类的变量和方法 ...

  8. 蓝缘管理系统第二个版本号开源了。springMVC+springSecurity3.x+Mybaits3.x 系统

    蓝缘管理系统第二个版本号开源了 继于 http://blog.csdn.net/mmm333zzz/article/details/16863543 版本号一.版本号二 对springMVC+spri ...

  9. 恢复js文件在windows默认打开方式

    解决办法: 运行 regedit 打开注册表编辑器,定位 "HKEY_CLASSES_ROOT" > ".js" 这一项,双击默认值将数值数据改为&quo ...

  10. 参数化测试--sheet表的应用

    自动化测试对录制和编辑好的测试步骤进行回放,这种是线性的自动化测试方式,其缺点是明显的,就是其测试覆盖面比较低.测试回放的只是录制时做出的界面操作,以及输入的测试数据,或者是脚本编辑时指定的界面操作和 ...