第八章. 依赖管理基础

Chapter 8. Dependency Management Basics

本章主要介绍 Gradle 依赖管理的一些基础知识。
This chapter introduces some of the basics of dependency management in Gradle.

8.1. 什么是依赖管理?

8.1. What is dependency management?

通俗来讲,依赖管理由两部分组成。首先,Gradle需要知道构建或运行你的项目所需要的东西,才能找到它们。 我们把这些传入的文件称为这个项目的 依赖。其次,Gradle需要构建并且上传你的项目所产生的东西,我们把这些输出的文件称为项目的 发布。下面详细介绍这两部分:
Very roughly, dependency management is made up of two pieces. Firstly, Gradle needs to know about the things that your project needs to build or run, in order to find them. We call these incoming files the dependencies of the project. Secondly, Gradle needs to build and upload the things that your project produces. We call these outgoing files the publications of the project. Let's look at these two pieces in more detail:

大部分项目都不是完全独立的,它们需要其他项目所构建的一些文件来编译或测试等等。例如,如果我想在我的项目中使用Hibernate,我需要在编译代码时把一些Hibernate的jar文件包含到类路径中。如果要运行测试,可能还需要把一些其他的jar包包含到测试类路径中,比如特定的JDBC驱动或者是Ehcache jar文件。
Most projects are not completely self-contained. They need files built by other projects in order to be compiled or tested and so on. For example, in order to use Hibernate in my project, I need to include some Hibernate jars in the classpath when I compile my source. To run my tests, I might also need to include some additional jars in the test classpath, such as a particular JDBC driver or the Ehcache jars.

这些传入的文件构成了这个项目的依赖。Gradle可以让你告诉它你项目的依赖是什么,以便它处理查找这些依赖,以及把它们加入构建。这些依赖可能需要从远程的Maven或Ivy仓库中下载,或者位于本地目录中,或是需要由同一个多项目构建的其他子项目来构建。这个过程我们称之为 依赖解析
These incoming files form the dependencies of the project. Gradle allows you to tell it what the dependencies of your project are, so that it can take care of finding these dependencies, and making them available in your build. The dependencies might need to be downloaded from a remote Maven or Ivy repository, or located in a local directory, or may need to be built by another project in the same multi-project build. We call this process dependency resolution.

通常一个项目的依赖还会有它们自己本身的依赖。例如Hibernate 核心类库在运行的时候就依赖于一些其他的类库。因此,当Gradle运行你的项目的测试用例时,它也需要找到这些依赖并使其可用。我们把这个过程称为 传递依赖
Often, the dependencies of a project will themselves have dependencies. For example, Hibernate core requires several other libraries to be present on the classpath with it runs. So, when Gradle runs the tests for your project, it also needs to find these dependencies and make them available. We call these transitive dependencies.

大多数项目的主要目的是构建一些在项目之外使用的文件。例如,如果你的项目是要生成一个Java库,你需要构建出一个jar文件,可能还需要一个源文件jar包,以及文档等,然后把它们发布出去。
The main purpose of most projects is to build some files that are to be used outside the project. For example, if your project produces a java library, you need to build a jar, and maybe a source jar and some documentation, and publish them somewhere.

这些输出文件构成了项目的发布内容。Gradle也会为你处理这个重要的事情。你声明项目的发布内容,Gradle就会负责构建它们并把它们发布到某个地方。“发布”的确切含义取决于你想做什么。你可能想把一些文件拷贝到一个本地的目录,把它们上传到一个远程的Maven或Ivy仓库,或是在同一个多项目构建的另一个子项目中使用这些文件。这个过程,我们称之为发布
These outgoing files form the publications of the project. Gradle also takes care of this important work for you. You declare the publications of your project, and Gradle take care of building them and publishing them somewhere. Exactly what "publishing" means depends on what you want to do. You might want to copy the files to a local directory, or upload them to a remote Maven or Ivy repository. Or you might use the files in another project in the same multi-project build. We call this process publication.

8.2. 依赖声明

8.2. Declaring your dependencies

我们来看一下一些依赖声明。下面是一个基本的构建脚本:
Let's look at some dependency declarations. Here's a basic build script:

示例 8.1. 依赖声明 - Example 8.1. Declaring dependencies

build.gradle

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
    testCompile group: 'junit', name: 'junit', version: '4.+'
}

这里做了些什么?这个构建脚本说明了关于项目的一些事情。首先,它指出,Hibernate core 3.6.7.Final是编项目的生产源代码所必需的。同时也暗指了,运行时还需要使用Hibernate core及其依赖。构建脚本还指出,编译项目的测试时需要4.0或以上的junit。它还告诉Gradle在Maven中央存储库中查找所需的任何依赖。以下各节内容会进行详细介绍。
What's going on here? This build script says a few things about the project. Firstly, it states that Hibernate core 3.6.7.Final is required to compile the project's production source. By implication, Hibernate core and its dependencies are also required at runtime. The build script also states that any junit >= 4.0 is required to compile the project's tests. It also tells Gradle to look in the Maven central repository for any dependencies that are required. The following sections go into the details.

8.3. 依赖配置

8.3. Dependency configurations

在Gradle中依赖会被分为几组配置。配置只是一组依赖的命名,我们会把它们称为依赖配置。你可以使用它们来声明项目的外部依赖。我们稍后会看到,它们也被用来声明你的项目的发布内容。
In Gradle dependencies are grouped into configurations. A configuration is simply a named set of dependencies. We will refer to them as dependency configurations. You can use them to declare the external dependencies of your project. As we will see later, they are also used to declare the publications of your project.

Java插件定义了许多标准配置。这些配置代表了Java插件使用的类路径。有些列在下面,你也可以在表23.5,“Java插件 - 依赖配置”了解到更多详细内容。
The Java plugin defines a number of standard configurations. These configurations represent the classpaths that the Java plugin uses. Some are listed below, and you can find more details in Table 23.5, “Java plugin - dependency configurations”.

compile

编译项目的生产源码所需的依赖。
The dependencies required to compile the production source of the project.

runtime

运行时生产类所需的依赖。默认情况下,也包括了编译时依赖。
The dependencies required by the production classes at runtime. By default, also includes the compile time dependencies.

testCompile

编译项目测试源码所需的依赖。默认情况下,还包括了所编译的生产类和编译时依赖。
The dependencies required to compile the test source of the project. By default, also includes the compiled production classes and the compile time dependencies.

testRuntime

运行测试所需的依赖。默认情况下,还包括编译,运行时及测试编译的依赖。
The dependencies required to run the tests. By default, also includes the compile, runtime and test compile dependencies.

各种插件添加了更多的标准配置。你也可以定义一些自定义配置以在构建中使用。有关定义和定制依赖配置的详细内容,请参见第50.3节,“依赖配置”
Various plugins add further standard configurations. You can also define your own custom configurations to use in your build. Please see Section 50.3, “Dependency configurations” for the details of defining and customizing dependency configurations.

8.4. 外部依赖

8.4. External dependencies

你可以声明多种类型的依赖。其中一种这样的类型叫外部依赖,它是依赖于在当前构建之外所生成的一些文件,并存储在某种存储库中,例如Maven Central,Maven私服,Ivy存储库,或者是本地文件系统中的某个目录。
There are various types of dependencies that you can declare. One such type is an external dependency. This a dependency on some files built outside the current build, and stored in a repository of some kind, such as Maven central, or a corporate Maven or Ivy repository, or a directory in the local file system.

要定义外部依赖,你需要把一个依赖添加到依赖配置中:
To define an external dependency, you add it to a dependency configuration:

示例8.2. 外部依赖的定义 - Example 8.2. Definition of an external dependency

build.gradle

dependencies {
    compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
}

一个外部依赖使用group, nameversion 属性来定义。根据你所使用的仓库类型不同, groupversion 可能是可选的。
An external dependency is identified using group, name and version attributes. Depending on which kind of repository you are using, group and version may be optional.

这里还有一种更加简洁的方式来声明外部依赖,它使用一个"group:name:version"形式的字符串。
There is a shortcut form for declaring external dependencies, which uses a string of the form "group:name:version".

示例8.3. 外部依赖的定义 - Example 8.3. Shortcut definition of an external dependency

build.gradle

dependencies {
    compile 'org.hibernate:hibernate-core:3.6.7.Final'
}

要了解有关定义和使用依赖的更多信息,请查看第50.4节,“如何声明你的依赖”
To find out more about defining and working with dependencies, have a look at Section 50.4, “How to declare your dependencies”.

8.5. 仓库

8.5. Repositories

Gradle是如何找到外部依赖的文件的呢?它通过在一个仓库去查找它们。仓库只是文件的一个集合,由groupnameversion来组织。 Gradle支持几种不同的仓库格式,例如Maven和Ivy;以及访问仓库的几种不同方法,例如使用本地文件系统或HTTP。
How does Gradle find the files for external dependencies? Gradle looks for them in a repository. A repository is really just a collection of files, organized by group, name and version. Gradle understands several different repository formats, such as Maven and Ivy, and several different ways of accessing the repository, such as using the local file system or HTTP.

默认情况下,Gradle没有定义任何仓库。需要你至少去定义一个,然后才能使用外部依赖。我们通常使用的有Maven中央仓库:
By default, Gradle does not define any repositories. You need to define at least one before you can use external dependencies. One option is use the Maven central repository:

示例8.4. 使用Maven中央仓库 - Example 8.4. Usage of Maven central repository

build.gradle

repositories {
    mavenCentral()
}

或其他远程Maven仓库:
Or a remote Maven repository:

示例8.5. 使用远程的Maven仓库 - Example 8.5. Usage of a remote Maven repository

build.gradle

repositories {
    maven {
        url "http://repo.mycompany.com/maven2"
    }
}

或者是一个远程的Ivy仓库:
Or a remote Ivy repository:

示例8.6. 使用远程Ivy目录 - Example 8.6. Usage of a remote Ivy directory

build.gradle

repositories {
    ivy {
        url "http://repo.mycompany.com/repo"
    }
}

你还可以在本地文件系统上部署一个仓库,它对于Maven和Ivy仓库都支持。
You can also have repositories on the local file system. This works for both Maven and Ivy repositories.

示例8.7. 使用本地Ivy目录 - Example 8.7. Usage of a local Ivy directory

build.gradle

repositories {
    ivy {
        // URL can refer to a local directory
        url "../local-repo"
    }
}

项目可以有多个仓库。 Gradle将按照指定的顺序在每个仓库中查找依赖,并在找到包含了所请求模块的第一个仓库后停止。
A project can have multiple repositories. Gradle will look for a dependency in each repository in the order they are specified, stopping at the first repository that contains the requested module.

要了解有关定义和使用仓库的更多信息,请查看第50.6节,“仓库”
To find out more about defining and working with repositories, have a look at Section 50.6, “Repositories”.

8.6. 发布构件

8.6. Publishing artifacts

依赖配置也用于发布文件。[3]我们称这些文件发布构件,通常也叫做构件
Dependency configurations are also used to publish files.[3] We call these files publication artifacts, or usually just artifacts.

插件对定义项目的构件提供了非常好的支持,所以通常无需再做其他事情来告诉Gradle需要发布什么。但是,你需要告诉Gradle发布到哪里。这就需要在uploadArchives任务中添加一个仓库。以下是发布到远程Ivy存储库的示例:
The plugins do a pretty good job of defining the artifacts of a project, so you usually don't need to do anything special to tell Gradle what needs to be published. However, you do need to tell Gradle where to publish the artifacts. You do this by attaching repositories to the uploadArchives task. Here's an example of publishing to a remote Ivy repository:

示例8.8. 发布到Ivy仓库 - Example 8.8. Publishing to an Ivy repository

build.gradle

uploadArchives {
    repositories {
        ivy {
            credentials {
                username "username"
                password "pw"
            }
            url "http://repo.mycompany.com"
        }
    }
}

现在,当你运行gradle uploadArchives,Gradle将会构建你的Jar包,以及生成ivy.xml并且一起上传。
Now, when you run gradle uploadArchives, Gradle will build and upload your Jar. Gradle will also generate and upload an ivy.xml as well.

当然,你也可以发布到Maven仓库。语法略有不同。[4]请注意,你需要应用Maven插件才能发布到Maven存储库。在这种情况下,Gradle也会生成pom.xml并上传。
You can also publish to Maven repositories. The syntax is slightly different.[4] Note that you also need to apply the Maven plugin in order to publish to a Maven repository. In this instance, Gradle will generate and upload a pom.xml.

示例8.9. 发布到Maven仓库 - Example 8.9. Publishing to a Maven repository

build.gradle

apply plugin: 'maven'

uploadArchives {
    repositories {
        mavenDeployer {
            repository(url: "file://localhost/tmp/myRepo/")
        }
    }
}

要了解有关发布的更多信息,请查看《第五十一章,发布构件》。
To find out more about publication, have a look at Chapter 51, Publishing artifacts.

8.7. 下一步目标?

8.7. Where to next?

有关依赖解析的所有细节,请参阅《第五十章,依赖管理》;而关于构件发布则请参阅《第五十一章, 发布构件》。
For all the details of dependency resolution, see Chapter 50, Dependency Management, and for artifact publication see Chapter 51, Publishing artifacts.

如果对这里提到的DSL元素感兴趣,请查看Project.configurations{}Project.repositories{}Project.dependencies{}
If you are interested in the DSL elements mentioned here, have a look at Project.configurations{}, Project.repositories{} and Project.dependencies{}.

另外,继续其他教程吧。
Otherwise, continue on to some of the other tutorials.



[3] 关于这点,我们认为会让人感到很困惑,因此我们正在逐渐梳理Gradle DSL中的这两个概念。
[3] We think this is confusing, and we are gradually teasing apart the two concepts in the Gradle DSL.

[4] 我们正在努力统一从Maven仓库解析依赖以及向其发布的语法。
[4] We are working to make the syntax consistent for resolving from and publishing to Maven repositories.