第五十章. 依赖管理

Chapter 50. Dependency Management

50.1. 介绍

50.1. Introduction

依赖管理是每个构建的关键特性,并且 Gradle 强调提供最好的依赖管理,容易理解以及使用各种各样的方法来兼容。如果您熟悉使用 Maven 或 Ivy 的方法,那么你会很高兴地知道,Gradle 完全兼容这两种方法,除此之外,它还有足够的灵活性,以支持完全自定义的方法。
Dependency management is a critical feature of every build, and Gradle has placed an emphasis on offering first-class dependency management that is both easy-to-understand and compatible with a wide variety of approaches. If you are familiar with the approach used by either Maven or Ivy you will be delighted to learn that Gradle is fully compatible with both approaches in addition to being flexible enough to support fully-customized approaches.

这里是 Gradle 支持的依赖管理的主要亮点:
Here are the major highlights of Gradle's support for dependency management:

  • 依赖管理传递: Gradle 赋予你对你的项目依赖项树的完全控制。


    Transitive dependency management: Gradle gives you full control of your project's dependency tree.

  • 对非管理依赖的支持:如果你的依赖只是版本控制下或共享的驱动器中的文件,Gradle 也提供了强大的功能以支持这种情况。


    Support for non-managed dependencies: If your dependencies are simply files in version control or a shared drive, Gradle provides powerful functionality to support this.

  • 支持依赖定义的自定义:Gradle 的模块依赖给你在构建脚本中描述依赖项层次结构的能力。


    Support for custom dependency definitions.: Gradle's Module Dependencies give you the ability to describe the dependency hierarchy in the build script.

  • 一个完全可自定义的依赖解析的方法:Gradle 为你提供了自定义解析规则的能力,让你可以轻松替换依赖。


    A fully customizable approach to Dependency Resolution: Gradle provides you with the ability to customize resolution rules making dependency substitution easy.

  • 完全兼容 Maven 和 Ivy :如果你已经在 Maven POM 文件或 Ivy 文件中定义了依赖,Gradle 提供了一系列受欢迎的构建工具可以进行无缝集成。


    Full Compatibility with Maven and Ivy: If you have defined dependencies in a Maven POM or an Ivy file, Gradle provide seamless integration with a range of popular build tools.

  • 与现有依赖管理基础结构的集成:Gradle 兼容 Maven 和 Ivy 仓库。如果你使用 Archiva, Nexus,或者是 Artifactory, Gradle 100% 兼容所有仓库的格式。


    Integration with existing dependency management infrastructure: Gradle is compatible with both Maven and Ivy repositories. If you use Archiva, Nexus, or Artifactory, Gradle is 100% compatible with all repository formats.

成千上万的开源组件互相依赖,每个组件都有一系列的版本及不兼容性,随着构建变得越来越复杂,依赖管理常常出现各种问题。当一个构建的依赖树变得笨拙时,你的构建工具不应该强迫你对依赖管理采取单一、不灵活的做法。一个正确的构建系统必须被设计得很灵活,而 Gradle 可以应付任何情况。
With hundreds of thousands of interdependent open source components each with a range of versions and incompatibilities, dependency management has a habit of causing problems as builds grow in complexity. When a build's dependency tree becomes unwieldy, your build tool shouldn't force you to adopt a single, inflexible approach to dependency management. A proper build system has to be designed to be flexible, and Gradle can handle any situation.

50.1.1. 为了迁移的灵活的依赖管理

50.1.1. Flexible dependency management for migrations

依赖管理在从一个构建系统迁移到另一个的过程中尤其具有挑战性。如果你从一个像 Ant 或 Maven 这样的工具迁移到 Gradle,你可能会面临一些困难的情况。例如,一个常见的模式是,有一个 Ant 项目,而它保存在文件系统中的一些 jar 文件缺少版本号。其他的构建系统在迁移之前需要对这种方法进行大量的替换。使用 Gradle,你可以让你的新构建适配任何现有的依赖来源或依赖元数据。这使得增量迁移到 Gradle 比其他的要容易得多。在大多数的大项目中,构建迁移和对发展过程的任何更改都是增量的,因为大多数组织不能负担得起停止一切事情并迁移到依赖管理的构建工具的想法。
Dependency management can be particularly challenging during a migration from one build system to another. If you are migrating from a tool like Ant or Maven to Gradle, you may be faced with some difficult situations. For example, one common pattern is an Ant project with version-less jar files stored in the filesystem. Other build systems require a wholesale replacement of this approach before migrating. With Gradle, you can adapt your new build to any existing source of dependencies or dependency metadata. This makes incremental migration to Gradle much easier than the alternative. On most large projects, build migrations and any change to development process is incremental because most organizations can't afford to stop everything and migrate to a build tool's idea of dependency management.

即使你的项目使用一个自定义的依赖管理系统,或者是一些像 Eclipse 作为依赖管理的主数据的 .classpath 文件,那么可以很容易地写一个 Gradle 插件在 Gradle 中使用此数据。出于迁移的目的,这是在 Gradle 中的一种常用技术。(但是,一旦你已经迁移,远离 .classpath 文件,直接使用 Gradle 的依赖管理功能会是一个好主意。)
Even if your project is using a custom dependency management system or something like an Eclipse .classpath file as master data for dependency management, it is very easy to write a Gradle plugin to use this data in Gradle. For migration purposes this is a common technique with Gradle. (But, once you've migrated, it might be a good idea to move away from a .classpath file and use Gradle's dependency management features directly.)

50.1.2. 依赖管理和 Java

50.1.2. Dependency management and Java

令人啼笑皆非的是,以其丰富的开源组件库著称的语言,Java 竟然没有库或者版本的概念。在 Java 中,没有标准的方法来告诉 JVM 你使用的是 3.0.5 版本的 Hibernate,也没有标准的方法来表明 foo-1.0.jar 依赖于 bar-2.0.jar。这导致了外部的解决方案通常都会基于构建工具。目前最受欢迎的解决方案是 Maven 和 Ivy。Maven 提供了一个完整的构建系统,而 Ivy 则完全着眼于依赖管理。
It is ironic that in a language known for its rich library of open source components that Java has no concept of libraries or versions. In Java, there is no standard way to tell the JVM that you are using version 3.0.5 of Hibernate, and there is no standard way to say that foo-1.0.jar depends on bar-2.0.jar. This has led to external solutions often based on build tools. The most popular ones at the moment are Maven and Ivy. While Maven provides a complete build system, Ivy focuses solely on dependency management.

这两种工具都依赖于描述符 XML 文件,包含有关具体某个 jar 的依赖的信息。这两者都使用了存储库,在存储库中实际的 jar 文件和它们的描述文件都放在一起,而且这两者通过窗口或其他的方式都提供了 jar 版本冲突的解决方案。这两者都已成为解决依赖冲突的标准,而 Gradle 最初使用的是 Ivy 引擎的依赖管理。Gradle 已经取代了 Ivy 上的直接依赖,而采用了原生的 Gradle 依赖解决引擎,它支持许多的依赖解决方案的方法,包括 POM 文件和 Ivy 描述文件。
Both tools rely on descriptor XML files, which contain information about the dependencies of a particular jar. Both also use repositories where the actual jars are placed together with their descriptor files, and both offer resolution for conflicting jar versions in one form or the other. Both have emerged as standards for solving dependency conflicts, and while Gradle originally used Ivy under the hood for its dependency management. Gradle has replaced this direct dependency on Ivy with a native Gradle dependency resolution engine which supports a range of approaches to dependency resolution including both POM and Ivy descriptor files.

50.2. 依赖管理的最佳实践

50.2. Dependency Management Best Practices

由于 Gradle 对依赖管理有强烈的主张,该工具使你可以选择两个选项之间:遵循推荐的最佳实践或支持任何你能想到的类型的模式。本节概述 Gradle 项目推荐的管理依赖的最佳实践。
While Gradle has strong opinions on dependency management, the tool gives you a choice between two options: follow recommended best practices or support any kind of pattern you can think of. This section outlines the Gradle project's recommended best practices for managing dependencies.

不管用什么语言,对每个项目而言,适当的依赖管理是很重要的。从一个由 Java 编写的依赖了数以百计开源库的复杂企业应用,再到依赖少量库的最简单的 Clojure 应用,依赖管理的办法大不相同,并且可以依赖于目标的技术、应用程序部署的方法和项目的性质。项目捆绑作为可重用的库,比起企业应用集成到更大的软件和基础设施的系统中,可能有不同的要求。尽管这一要求变化很大,Gradle 项目建议所有项目都遵循这套核心规则:
No matter what the language, proper dependency management is important for every project. From a complex enterprise application written in Java depending on hundreds of open source libraries to the simplest Clojure application depending on a handful of libraries, approaches to dependency management vary widely and can depend on the target technology, the method of application deployment, and the nature of the project. Projects bundled as reusable libraries may have different requirements than enterprise applications integrated into much larger systems of software and infrastructure. Despite this wide variation of requirements, the Gradle project recommends that all projects follow this set of core rules:

50.2.1. 在文件名中包含版本号(版本化 jar 文件)

50.2.1. Put the Version in the Filename (Version the jar)

在文件名中库的版本必须是容易辨认的。Jar 的版本通常是在清单文件中,当你要检查一个项目时它并不显而易见。如果有人让你看 20 个 jar 文件,你更喜欢哪一种?一个文件命名为 beanutils-beanutils-1.3.jar 的集合,还是文件命名为 spring.jar 的集合?如果依赖的文件名称带有版本号,那么将更容易快速确定依赖的版本。
The version of a library must be easy to recognize in the filename. While the version of a jar is usually in the Manifest file, it isn't readily apparent when you are inspecting a project. If someone asks you to look at a collection of 20 jar files, which would you prefer? A collection of files with names like commons-beanutils-1.3.jar or a collection of files with names like spring.jar? If dependencies have file names with version numbers it is much easier to quickly identify the versions of your dependencies.

如果版本不清楚,你可能引入一些很难找到的微妙的错误。例如可能有一个项目使用 Hibernate 2.5。想一下一个开发人员决定在她的机器安装 3.0.5 的版本,以修复一个关键的安全 bug,但她忘记通知其他团队这个变化。她可能成功地解决了这个安全 bug,但她也可能有引入一些 bug 到代码库中,因为项目用到了 Hibernate 现在弃用的功能。一周后在集成的机器上可能会有一个异常,而这个异常无法在任何人的机器上复现。然后多个开发人员花了数天的时间在这个问题上,终于意识到如果他们知道 Hibernate 已经从 2.5 升级到 3.0.5,这个错误会很容易发现。
If versions are unclear you can introduce subtle bugs which are very hard to find. For example there might be a project which uses Hibernate 2.5. Think about a developer who decides to install version 3.0.5 of Hibernate on her machine to fix a critical security bug but forgets to notify others in the team of this change. She may address the security bug successfully, but she also may have introduced subtle bugs into a codebase that was using a now-deprecated feature from Hibernate. Weeks later there is an exception on the integration machine which can't be reproduced on anyone's machine. Multiple developers then spend days on this issue only finally realising that the error would have easy to uncover if they knew that Hibernate had been upgraded from 2.5 to 3.0.5.

在 jar 文件中包含版本号提高了在你的项目中的表现,并且让它们更易于维护。这种做法也减少了潜在的错误。
Versions in jar names increase the expressiveness of your project and make them easier to maintain. This practice also reduces the potential for error.

50.2.2. 管理传递依赖

50.2.2. Manage transitive dependencies

传递依赖管理是一种技术,让你的项目能够依赖那些反过来依赖其他库的库。这种递归模式传递依赖的结果是,在一个依赖树中,会包含你的项目的第一级依赖、第二级依赖,等等。如果你不把你的依赖作为层次结构树的第一级和第二级依赖的模型,那么在对未组织的依赖进行混乱的组装之后,就会很容易地失去控制。考虑 Gradle 项目本身,虽然 Gradle 仅有几个直接的第一级依赖,当 编译 Gradle 时在它的类路径上会需要超过一百个的依赖。在更大的规模上,使用 Spring,Hibernate和其他的库,旁边数百或数千个内部项目的企业应用,也有非常大的依赖树。
Transitive dependency management is a technique that enables your project to depend on libraries which, in turn, depend on other libraries. This recursive pattern of transitive dependencies results in a tree of dependencies including your project's first-level dependencies, second-level dependencies, and so on. If you don't model your dependencies as a hierarchical tree of first-level and second-level dependencies it is very easy to quickly lose control over an assembled mess of unstructured dependencies. Consider the Gradle project itself, while Gradle only has a few direct, first-level dependencies, when Gradle is compiled it needs more that one hundred dependencies on the classpath. On a far larger scale, Enterprise projects using Spring, Hibernate, and other libraries, alongside hundreds or thousands of internal projects can have very large dependency trees.

当这些大的依赖树需要更改时,你经常得解决一些依赖的版本冲突。比如说一个开源库需要一个日志库的一个版本,而另一个库需要日志库的另一个版本。Gradle 和其他的构建工具都能够处理这种关系树和解决冲突问题,但不同的是,Gradle 让你可以控制传递依赖和冲突的解决。
When these large dependency trees need to change, you'll often have to solve some dependency version conflicts. Say one open source library needs one version of a logging library and a another uses an alternative version. Gradle and other build tools all have the ability to solve this dependency tree and resolve conflicts, but what differentiates Gradle is the control it gives you over transitive dependencies and conflict resolution.

虽然你可以尝试手动管理这个问题,你很快就会发现这种方法不能扩展。如果你想要摆脱第一级的依赖,你不能真正确定还有哪些 jar 文件你是需要删除的。第一级依赖的依赖项也可能是第一级依赖本身,或者也可能是另一个第一级依赖的传递依赖。如果你尝试自己管理传递依赖,最终的结果是你的构建会变得很脆弱:没有人敢去改变你的依赖,因为破坏构建的风险太高。项目的类路径会变得一片狼藉,并且,如果类路径出现问题时,那简直就是人间地狱。
While you could try to manage this problem manually, you will quickly find that this approach doesn't scale. If you want to get rid of a first level dependency you really can't be sure which other jars you should remove. A dependency of a first level dependency might also be a first level dependency itself, or it might be a transitive dependency of yet another first level dependency. If you try to manage transitive dependencies yourself, the end of the story is that your build becomes brittle: no one dares to change your dependencies because the risk of breaking the build is too high. The project classpath becomes a complete mess, and, if a classpath problem arises, hell on earth invites you for a ride.

注:
NOTE:
在一个项目中,我们发现在类路径中有一个神秘、LDAP 相关的 jar 包。没有代码引用这个 jar 包,这个 jar 包也与该项目没有任何连接。没人能弄清楚这个 jar 包是干什么用的,直到它被从构建中移除,然后应用在试图向 LDAP 进行身份验证的时候,遇到了很大的性能问题。这个神秘的 jar 包是一个必需传递的,第四级的依赖,很容易被忽略,因为没有人会费心去使用托管的传递依赖。

Gradle 向你提供了不同的方式来表达第一级的和传递的依赖。通过 Gradle 你可以混合使用和适配一些方法;例如,你可以在 SCM 中存储你的 jar 包,而不需要 XML 描述符文件,并且仍然使用传递依赖管理。
Gradle offers you different ways to express first-level and transitive dependencies. With Gradle you can mix and match approaches; for example, you could store your jars in an SCM without XML descriptor files and still use transitive dependency management.

50.2.3. 解决版本冲突的问题

50.2.3. Resolve version conflicts

相同的 jar 包的冲突版本应该被检测到,并且要么解决,要么抛出异常。如果你不使用传递依赖管理,版本冲突没被发现,那么在类路径中无法预测的顺序,将导致不知道会使用哪一个版本的依赖。对于许多开发人员都会更改依赖的大型项目,成功的构建将会少之又少,因为依赖的顺序可能会直接影响到构建是否成功(或者在产品中是否会出现一个 bug)。
Conflicting versions of the same jar should be detected and either resolved or cause an exception. If you don't use transitive dependency management, version conflicts are undetected and the often accidental order of the classpath will determine what version of a dependency will win. On a large project with many developers changing dependencies, successful builds will be few and far between as the order of dependencies may directly affect whether a build succeeds or fails (or whether a bug appears or disappears in production).

如果你还没有处理过在类路径中 jar 包版本冲突的麻烦,这里有一个小趣闻等着你。在一个有30个子模块的大型项目中,向子项目添加的一个依赖改变了类路径的顺序, Spring 2.5 与老的 2.4 版本的顺序被交换。虽然可以继续构建,开发者已经开始注意到在生产中出现了各种令人惊讶(和惊人可怕)的 bug。然而,更糟糕的是,无意降低版本的 Spring 向系统引入了几个安全漏洞,现在需要在整个组织中进行全面的安全审核。
If you haven't had to deal with the curse of conflicting versions of jars on a classpath, here is a small anecdote of the fun that awaits you. In a large project with 30 submodules, adding a dependency to a subproject changed the order of a classpath, swapping Spring 2.5 for an older 2.4 version. While the build continued to work, developers were starting to notice all sorts of surprising (and surprisingly awful) bugs in production. Worse yet, this unintentional downgrade of Spring introduced several security vulnerabilities into the system, which now required a full security audit throughout the organization.

总之,版本冲突是很不好的,你应该管理你的传递依赖,以避免它们。你也可能想要了解版本冲突用到的地方,并且在你的整个组织中统一一个指定版本的依赖。通过一个好的冲突报告工具,像 Gradle,这些信息可以用于与整个组织沟通,并在一个单一的版本上实现标准化。如果你觉得你不会发生版本冲突,再想想。 不同的第一级依赖,依赖于一系列不同的重叠版本的其他依赖,这种情况是很常见的,而 JVM 还不能提供简单的方法,使得能在类路径中让相同的 jar 包可以有不同的版本(请参阅第 50.1.2 节,“依赖管理和 Java”)。
In short, version conflicts are bad, and you should manage your transitive dependencies to avoid them. You might also want to learn where conflicting versions are used and consolidate on a particular version of a dependency across your organization. With a good conflict reporting tool like Gradle, that information can be used to communicate with the entire organization and standardize on a single version. If you think version conflicts don't happen to you, think again. It is very common for different first-level dependencies to rely on a range of different overlapping versions for other dependencies, and the JVM doesn't yet offer an easy way to have different versions of the same jar in the classpath (see Section 50.1.2, “Dependency management and Java”).

Gradle 提供了以下的冲突解决策略:
Gradle offers the following conflict resolution strategies:

  • Newest:使用最新版本的依赖这是 Gradle 的默认策略,只要版本都能向后兼容,往往是合适的选择。
    Newest: The newest version of the dependency is used. This is Gradle's default strategy, and is often an appropriate choice as long as versions are backwards-compatible.
  • Fail:一个版本冲突将导致构建失败。这种策略强制在构建脚本中明确地解决所有的版本冲突。有关如何显式选择一个特定版本的详细信息,请参阅ResolutionStrategy
    Fail: A version conflict results in a build failure. This strategy enforces that all version conflicts are resolved explicitly in the build script. See ResolutionStrategy for details on how to explicitly choose a particular version.

虽然上面介绍的策略通常足够解决大部分的冲突,但是 Gradle 也提供更细粒度的机制,以解决版本冲突:
While the strategies introduced above are usually enough to solve most conflicts, Gradle provides more fine-grained mechanisms to resolve version conflicts:

  • 强制配置第一级依赖。如果冲突中的依赖已经是第一级的依赖,那么这种方法会很有用。请参阅DependencyHandler中的示例。
    Configuring a first level dependency as forced. This approach is useful if the dependency in conflict is already a first level dependency. See examples in DependencyHandler.
  • 强制配置任何依赖项(不管是否可传递)。如果冲突中的依赖是传递依赖,那么这种方法会很有用。它也可以用于强制第一级依赖的版本。请参阅ResolutionStrategy中的示例。
    Configuring any dependency (transitive or not) as forced. This approach is useful if the dependency in conflict is a transitive dependency. It also can be used to force versions of first level dependencies. See examples in ResolutionStrategy
  • 依赖解析规则是一个在 Gradle 1.4 引进的孵化中的功能,让你可以对特定的依赖细粒度地控制所选定的版本。
    Dependency resolve rules are an incubating feature introduced in Gradle 1.4 which give you fine-grained control over the version selected for a particular dependency.

为了解决版本冲突问题,报告依赖关系图也是很有帮助的。这些报告是依赖管理的另一个功能。
To deal with problems due to version conflicts, reports with dependency graphs are also very helpful. Such reports are another feature of dependency management.

50.2.4. 使用动态版本和变化的模块

50.2.4. Use Dynamic Versions and Changing Modules

有许多情况,是你想要使用一个特定依赖的最新版本,或者是某个版本范围内的最新版。这可以是在开发中需要,或者你可能正在开发一个库,它被设计为使用一个范围内的依赖版本。你可以通过使用动态版本很容易地依赖这些不断变化的依赖。一个动态的版本可以是一个版本范围(例如2.+),也可以是表示可用的最新版本的占位符(例如latest.integration)。
There are many situation when you want to use the latest version of a particular dependency, or the latest in a range of versions. This can be a requirement during development, or you may be developing a library that is designed to work with a range of dependency versions. You can easily depend on these constantly changing dependencies by using a dynamic version. A dynamic version can be either a version range (e.g. 2.+) or it can be a placeholder for the latest version available (e.g. latest.integration).

另外,你请求的模块随着时间推移,即使是同一版本,有时也可能改变了。这种变化模块的类型的一个例子是 MavenSNAPSHOT模块,它总是指向最新发布的构件。换句话说,一个标准的 Maven snapshot 是一个这样的模块,它永远不会不变,可以说,它是“不断变化的模块”。
Alternatively, sometimes the module you request can change over time, even for the same version. An example of this type of changing module is a Maven SNAPSHOT module, which always points at the latest artifact published. In other words, a standard Maven snapshot is a module that never stands still so to speak, it is a "changing module".

动态版本变化模块的主要区别是,当你解析一个动态版本时,你会得到真正的、 静态的版本作为模块名称。当你解析一个变化模块时,这个 artifacts 使用你请求的版本进行命名,但下层的 artifacts 可能随时会有变化。
The main difference between a dynamic version and a changing module is that when you resolve a dynamic version, you'll get the real, static version as the module name. When you resolve a changing module, the artifacts are named using the version you requested, but the underlying artifacts may change over time.

默认情况下,Gradle 对动态版本和变化模块的缓存时间是24小时。你可以使用命令行选项重写默认的缓存模式。你可以通过resolution strategy修改你的构建的缓存到期时间(见第 50.9.3 节,“调整控制依赖缓存”)。
By default, Gradle caches dynamic versions and changing modules for 24 hours. You can override the default cache modes using command line options. You can change the cache expiry times in your build using the resolution strategy (see Section 50.9.3, “Fine-tuned control over dependency caching”).

50.3. 依赖配置

50.3. Dependency configurations

在 Gradle 中,依赖被分组到配置中。配置有一个名字和许多属性,并且它们能够互相继承。许多 Gradle 插件会向你的 project 添加预定义的配置。例如,Java 插件会添加一些配置来表示它所需要的不同的类路径。详细信息请参阅第 23.5 节,“依赖管理” 。当然,你可以添加自定义配置到这上面。关于自定义配置,有许多的用例。这是非常方便的,例如添加依赖时不需要构建或测试你的软件(比如,将会与发布的软件一起的额外的 JDBC 驱动程序)。
In Gradle dependencies are grouped into configurations. Configurations have a name, a number of other properties, and they can extend each other. Many Gradle plugin add pre-defined configurations to your project. The Java plugin, for example, adds some configurations to represent the various classpaths it needs. see Section 23.5, “Dependency management” for details. Of course you can add custom configurations on top of that. There are many use cases for custom configurations. This is very handy for example for adding dependencies not needed for building or testing your software (e.g. additional JDBC drivers to be shipped with your distribution).

一个项目的配置被一个 configurations 对象所管理。你传给这个 configurations 对象的闭包会通过它对应的 API 被应用。要了解更多关于此 API 的内容,可以看看ConfigurationContainer
A project's configurations are managed by a configurations object. The closure you pass to the configurations object is applied against its API. To learn more about this API have a look at ConfigurationContainer.

如果要定义配置:
To define a configuration:

示例 50.1. 配置的定义 - Example 50.1. Definition of a configuration

build.gradle

configurations {
    compile
}

如果要访问配置:
To access a configuration:

示例 50.2. 访问配置 - Example 50.2. Accessing a configuration

build.gradle

println configurations.compile.name
println configurations['compile'].name

配置一个配置:
To configure a configuration:

示例 50.3. 配置一个配置 - Example 50.3. Configuration of a configuration

build.gradle

configurations {
    compile {
        description = 'compile classpath'
        transitive = true
    }
    runtime {
        extendsFrom compile
    }
}
configurations.compile {
    description = 'compile classpath'
}

50.4. 如何声明依赖

50.4. How to declare your dependencies

你可以声明几种不同类型的依赖:
There are several different types of dependencies that you can declare:

表 50.1. 依赖类型 - Table 50.1. Dependency types

类型
Type
描述
Description
外部模块依赖
External module dependency
对一些仓库中的外部模块的依赖
A dependency on an external module in some repository.
项目依赖
Project dependency
在同一个构建中对另一个项目的依赖
A dependency on another project in the same build.
文件依赖
File dependency
对本地文件系统中的一些文件的依赖
A dependency on a set of files on the local filesystem.
客户端模块依赖
Client module dependency
对外部模块的依赖,该块部模块的 artifacts 存储于一些仓库中,但是模块的元数据由本地构建指定。当你想要重写模块的元数据时,你可以使用这种类型的依赖。
A dependency on an external module, where the artifacts are located in some repository but the module meta-data is specified by the local build. You use this kind of dependency when you want to override the meta-data for the module.
Gradle API 依赖
Gradle API dependency
对当前的 Gradle 版本的 API 的依赖当你正在开发自定义的 Gradle 插件和任务类型时,你可以使用这种类型的依赖。
A dependency on the API of the current Gradle version. You use this kind of dependency when you are developing custom Gradle plugins and task types.
本地的 Groovy 依赖
Local Groovy dependency
对当前的 Gradle 所使用的 Groovy 版本的依赖。当你正在开发自定义的 Gradle 插件和任务类型时,你可以使用这种类型的依赖。
A dependency on the Groovy version used by the current Gradle version. You use this kind of dependency when you are developing custom Gradle plugins and task types.

50.4.1. 外部模块依赖

50.4.1. External module dependencies

外部模块依赖是最常见的依赖。它们引用外部仓库中的模块。
External module dependencies are the most common dependencies. They refer to a module in an external repository.

示例 50.4. 模块依赖 - Example 50.4. Module dependencies

build.gradle

dependencies {
    runtime group: 'org.springframework', name: 'spring-core', version: '2.5'
    runtime 'org.springframework:spring-core:2.5', 'org.springframework:spring-aop:2.5'
    runtime(
        [group: 'org.springframework', name: 'spring-core', version: '2.5'],
        [group: 'org.springframework', name: 'spring-aop', version: '2.5']
    )
    runtime('org.hibernate:hibernate:3.0.5') {
        transitive = true
    }
    runtime group: 'org.hibernate', name: 'hibernate', version: '3.0.5', transitive: true
    runtime(group: 'org.hibernate', name: 'hibernate', version: '3.0.5') {
        transitive = true
    }
}

有关更多的例子和完整的参考,请参阅DependencyHandler
See DependencyHandler for more examples and a complete reference.

Gradle 为模块依赖提供了不同的标记法。有 string 标记法和 map 标记法。模块依赖有一个 API,用于进行进一步的配置。要了解所有该 API 的内容,可以参阅ExternalModuleDependency 。该 API 提供了一些属性和配置方法。通过 string 标记法,你可以定义一个属性的子集。而通过使用 map 标记法,你可以定义所有的属性。要访问完整的 API,使用 map 或 string 标记法,你可以把单个的依赖与一个闭包一起指定给一个配置。
Gradle provides different notations for module dependencies. There is a string notation and a map notation. A module dependency has an API which allows for further configuration. Have a look at ExternalModuleDependency to learn all about the API. This API provides properties and configuration methods. Via the string notation you can define a subset of the properties. With the map notation you can define all properties. To have access to the complete API, either with the map or with the string notation, you can assign a single dependency to a configuration together with a closure.

如果你定义了一个模块依赖,Gradle 会在仓库中查找相应的模块描述符文件(pom.xmlivy.xml)。如果存在此类模块描述符文件,它会进行分析,并下载此模块的 artifacts (例如hibernate-3.0.5.jar)以及其依赖项(例如 cglib)。如果不存在这样的模块描述符文件,Gradle 会查找一个hibernate-3.0.5.jar 文件。在 Maven 中,一个模块仅能有一个 artifact。在 Gradle 和 Ivy 中,一个模块可以具有多个 artifacts。每个 artifact 可以有一组不同的依赖。
If you declare a module dependency, Gradle looks for a corresponding module descriptor file (pom.xml or ivy.xml) in the repositories. If such a module descriptor file exists, it is parsed and the artifacts of this module (e.g. hibernate-3.0.5.jar) as well as its dependencies (e.g. cglib) are downloaded. If no such module descriptor file exists, Gradle looks for a file called hibernate-3.0.5.jar to retrieve. In Maven, a module can have one and only one artifact. In Gradle and Ivy, a module can have multiple artifacts. Each artifact can have a different set of dependencies.

50.4.1.1. 依赖有多个 artifacts 的模块

50.4.1.1. Depending on modules with multiple artifacts
正如前面提到的,一个 Maven 模块都只有一个 artifact。因此,当你的项目依赖于一个 Maven 模块时,这个模块的 artifact 是哪一个会很明显。而使用 Gradle 或Ivy的话,情况就不同了。Ivy 的依赖描述符( ivy.xml)可以定义多个 artifact。有关更多的信息,请参阅 ivy.xml引用的Ivy。在 Gradle 中,当你声明一个对 Ivy 模块的依赖时,实际上你是在那个模块的 default 配置上声明了一个依赖。所以实际上,你依赖的 artifacts 集(通常是一些 jar 包) 是与该模块的 default 配置相关联的 artifacts 集。以下是一些比较重要的情况:
  • 一个模块的 default 配置包含了不希望有的 artifacts。一个依赖只是声明了所需的 artifacts ,而不是依赖整个配置。
    The default configuration of a module contains undesired artifacts. Rather than depending on the whole configuration, a dependency on just the desired artifacts is declared.
  • 所需的 artifact 属于一个非 default的配置。这个配置被显式地命名为这个依赖声明的一部分。
    The desired artifact belongs to a configuration other than default. That configuration is explicitly named as part of the dependency declaration.
还有一些其他的情况,需要调整依赖声明。请参阅 DependencyHandler 的例子和声明依赖的完整参考。

50.4.1.2. Artifact only notation

50.4.1.2. Artifact only notation

如上所述,如果找不到模块的描述符文件,默认情况下 Gradle 会下载一个与模块的名称相同的 jar 文件。但有时候,即使存储库包含了模块描述符,而你只是想下载 artifact jar而不下载它的依赖项。[14] 而有时候你想要从一个仓库中下载一个 zip,而它没有模块描述符。Gradle 提供了一个 artifact only notation 用于这些案例情况——只是对你想要下载的扩展前加个 '@' 标志:
As said above, if no module descriptor file can be found, Gradle by default downloads a jar with the name of the module. But sometimes, even if the repository contains module descriptors, you want to download only the artifact jar, without the dependencies. [14] And sometimes you want to download a zip from a repository, that does not have module descriptors. Gradle provides an artifact only notation for those use cases - simply prefix the extension that you want to be downloaded with '@' sign:

示例 505. Artifact only notation - Example 50.5. Artifact only notation

build.gradle

dependencies {
    runtime "org.groovy:groovy:2.2.0@jar"
    runtime group: 'org.groovy', name: 'groovy', version: '2.2.0', ext: 'jar'
}


一个 artifact only notation 创建了一个模块依赖,它只下载指定扩展名的 artifact 文件。现有的模块描述符将被忽略。

An artifact only notation creates a module dependency which downloads only the artifact file with the specified extension. Existing module descriptors are ignored.

50.4.1.3. Classifiers

50.4.1.3. Classifiers

Maven 依赖管理有 classifier 的概念。[15] 而 Gradle 支持这一点。如果你想从一个 Maven 仓库中获取 classified 依赖项,你可以这样写:
The Maven dependency management has the notion of classifiers. [15] Gradle supports this. To retrieve classified dependencies from a Maven repository you can write:

示例 50.6. 使用 classifier 的依赖 - Example 50.6. Dependency with classifier

build.gradle

compile "org.gradle.test.classifiers:service:1.0:jdk15@jar"
    otherConf group: 'org.gradle.test.classifiers', name: 'service', version: '1.0', classifier: 'jdk14'

如上面的第一行所示,classifiers 可以与artifact only notation 一起使用。
As can be seen in the first line above, classifiers can be used together with artifact only notation.

它可以轻松地遍历一个配置的依赖 artifacts:
It is easy to iterate over the dependency artifacts of a configuration:

示例 50.7. 遍历一个配置 - Example 50.7. Iterating over a configuration

build.gradle

task listJars << {
    configurations.compile.each { File file -> println file.name }
}

gradle -q listJars的输出结果
Output of gradle -q listJars

> gradle -q listJars
hibernate-core-3.6.7.Final.jar
antlr-2.7.6.jar
commons-collections-3.1.jar
dom4j-1.6.1.jar
hibernate-commons-annotations-3.2.0.Final.jar
hibernate-jpa-2.0-api-1.0.1.Final.jar
jta-1.1.jar
slf4j-api-1.6.1.jar

50.4.2. 客户端模块依赖

50.4.2. Client module dependencies

客户端模块依赖允许直接在构建脚本中声明传递依赖。它们是外部库的模块描述符的替代者。
Client module dependencies allow to declare transitive dependencies directly in the build script. They are a replacement for a module descriptor in an external repository.

示例 50.8. 客户端模块依赖 - 传递依赖 - Example 50.8. Client module dependencies - transitive dependencies

build.gradle

dependencies {
    runtime module("org.codehaus.groovy:groovy-all:2.2.0") {
        dependency("commons-cli:commons-cli:1.0") {
            transitive = false
        }
        module(group: 'org.apache.ant', name: 'ant', version: '1.9.3') {
            dependencies "org.apache.ant:ant-launcher:1.9.3@jar", "org.apache.ant:ant-junit:1.9.3"
        }
    }
}

这里定义了一个对 Groovy 的依赖。Groovy 本身具有依赖。但 Gradle 不会去查找一个 XML 描述符来找出它的依赖,而是从构建文件中获取信息。一个客户端模块的依赖可以是正常的模块依赖,或者是 artifact 依赖项或是另一个客户端模块。可以看一看 API 文档: ClientModule
This declares a dependency on Groovy. Groovy itself has dependencies. But Gradle does not look for an XML descriptor to figure them out but gets the information from the build file. The dependencies of a client module can be normal module dependencies or artifact dependencies or another client module. Have also a look at the API documentation: ClientModule

在当前版本客户端模块有一个缺陷。假设你的项目是一个库,你想要这个库上传到你公司的 Maven 或Ivy 仓库。Gradle 会将你的项目的 jar 包以及这仆依赖的 XML 描述文件上传到公司仓库。如果你使用了客户端模块,在 XML 描述符文件中的依赖声明就会不正确。我们将在未来版本的 Gradle 修正这一点。
In the current release client modules have one limitation. Let's say your project is a library and you want this library to be uploaded to your company's Maven or Ivy repository. Gradle uploads the jars of your project to the company repository together with the XML descriptor file of the dependencies. If you use client modules the dependency declaration in the XML descriptor file is not correct. We will improve this in a future release of Gradle.

50.4.3. 项目依赖

50.4.3. Project dependencies

对于多项目构建,Gradle 能区分外部依赖与作为多项目构建的一部分的某个项目上的依赖。对于后者,你可以声明项目依赖
Gradle distinguishes between external dependencies and dependencies on projects which are part of the same multi-project build. For the latter you can declare Project Dependencies.

50.9. 项目依赖 - Example 50.9. Project dependencies

build.gradle

dependencies {
    compile project(':shared')
}

详细信息请参阅ProjectDependency的 API 文档
For more information see the API documentation for ProjectDependency

多项目构建将在第 56 章,多项目生成中进行详述。
Multi-project builds are discussed inChapter 56, Multi-project Builds.

50.4.4. 文件依赖

50.4.4. File dependencies

文件依赖允许你直接将一组文件添加到配置中,而不用先将它们添加到存储库。这将会非常有用,比如你无法,或者是不想要把某些文件放到仓库。或者是你如果不想使用任何仓库来存储你的依赖。
File dependencies allow you to directly add a set of files to a configuration, without first adding them to a repository. This can be useful if you cannot, or do not want to, place certain files in a repository. Or if you do not want to use any repositories at all for storing your dependencies.

如果想添加一些文件作为配置的依赖,你只需要传一个文件集合作为依赖:
To add some files as a dependency for a configuration, you simply pass a file collection as a dependency:

示例 50.10. 文件依赖 - Example 50.10. File dependencies

build.gradle

dependencies {
    runtime files('libs/a.jar', 'libs/b.jar')
    runtime fileTree(dir: 'libs', include: '*.jar')
}

文件依赖项不会包含在你的项目的发布的依赖描述中。然而,文件依赖会被包含在同一个构建的传递项目依赖里。这意味着它们不能在当前的构建外使用,但它们可以在同一个构建中使用。
File dependencies are not included in the published dependency descriptor for your project. However, file dependencies are included in transitive project dependencies within the same build. This means they cannot be used outside the current build, but they can be used with the same build.

你可以声明哪些任务将产生作为文件依赖的文件。例如,你可以在通过构建生成文件的时候这样做。
You can declare which tasks produce the files for a file dependency. You might do this when, for example, the files are generated by the build.

示例 50.11. 生成文件依赖 - Example 50.11. Generated file dependencies

build.gradle

dependencies {
    compile files("$buildDir/classes") {
        builtBy 'compile'
    }
}

task compile << {
    println 'compiling classes'
}

task list(dependsOn: configurations.compile) << {
    println "classpath = ${configurations.compile.collect {File file -> file.name}}"
}

gradle -q list的输出结果
Output of gradle -q list

> gradle -q list
compiling classes
classpath = [classes]

50.4.5. Gradle API 依赖

50.4.5. Gradle API Dependency

你可以通过使用DependencyHandler.gradleApi()方法,来声明一个当前的 Gradle 版本的 API 上的依赖。当你在开发自定义 Gradle 任务或插件时将会很有用。
You can declare a dependency on the API of the current version of Gradle by using the DependencyHandler.gradleApi() method. This is useful when you are developing custom Gradle tasks or plugins.

示例 50.12. Gradle API 依赖 - Example 50.12. Gradle API dependencies

build.gradle

dependencies {
    compile gradleApi()
}

50.4.6. 本地 Groovy 依赖

50.4.6. Local Groovy Dependency

可以通过使用DependencyHandler.localGroovy()方法,来声明对与 Gradle 一起发布的 Groovy 的依赖。当你在开发自定义 Gradle 任务或在 Groovy 中的插件时将会很有用。
You can declare a dependency on the Groovy that is distributed with Gradle by using the DependencyHandler.localGroovy() method. This is useful when you are developing custom Gradle tasks or plugins in Groovy.

示例 50.13. Gradle 的 Groovy 依赖 - Example 50.13. Gradle's Groovy dependencies

build.gradle

dependencies {
    compile localGroovy()
}

50.4.7. 排除传递依赖

50.4.7. Excluding transitive dependencies

通过配置或者是通过依赖,你可以排除一个传递依赖:
You can exclude a transitive dependency either by configuration or by dependency:

示例 50.14. 排除传递依赖 - Example 50.14. Excluding transitive dependencies

build.gradle

configurations {
    compile.exclude module: 'commons'
    all*.exclude group: 'org.gradle.test.excludes', module: 'reports'
}

dependencies {
    compile("org.gradle.test.excludes:api:1.0") {
        exclude module: 'shared'
    }
}

如果你为一个特定的配置定义一个 exclude,则解析此配置或任何继承的配置时,对于所有的依赖,所排除的传递依赖将会被过滤掉。如果你想要从你的所有配置中排除传递依赖,你可以用简明的方式,使用 Groovy 的 spread-dot 运算符来表示,如这个例子所示例。在定义一个 exclude 时,你可以只指定 organization 或者 module 名称,或者是两者都指定。可以看看 DependencyConfiguration 的 API 文档。
If you define an exclude for a particular configuration, the excluded transitive dependency will be filtered for all dependencies when resolving this configuration or any inheriting configuration. If you want to exclude a transitive dependency from all your configurations you can use the Groovy spread-dot operator to express this in a concise way, as shown in the example. When defining an exclude, you can specify either only the organization or only the module name or both. Have also a look at the API documentation of Dependency and Configuration.

不是每个传递依赖都可以被排除 — — 一些传递依赖可能是应用程序能正确运行的必要条件。一般来说,可以被排除的传递依赖,在运行时并不需要,或者是保证在目标环境或平台上可用。
Not every transitive dependency can be excluded - some transitive dependencies might be essential for correct runtime behavior of the application. Generally, one can exclude transitive dependencies that are either not required by runtime or that are guaranteed to be available on the target environment/platform.

你应排除每个依赖或每个配置吗?事实证明,在大多数情况下你想要排除每一个配置。下面是为什么可能想要排除传递依赖的一些原因。记住,对于其中一些用例,有着比排除更好的解决方案!
Should you exclude per-dependency or per-configuration? It turns out that in majority of cases you want to use the per-configuration exclusion. Here are the some exemplary reasons why one might want to exclude a transitive dependency. Bear in mind that for some of those use cases there are better solutions than exclusions!

  • 由于许可证的原因而让依赖不受欢迎。
    The dependency is undesired due to licensing reasons.
  • 在任何的远程仓库中这个依赖都不可用。
    The dependency is not available in any of remote repositories.
  • 在运行时不需要这个依赖。
    The dependency is not needed for runtime.
  • 这个依赖有一个版本与所需要的版本冲突。使用这个案例,请参考第 50.2.3 节,“解决版本冲突”和关于ResolutionStrategy文档,以了解这个问题潜在的更好的解决方案。
    The dependency has a version that conflicts with a desired version. For that use case please refer to Section 50.2.3, “Resolve version conflicts” and the documentation on ResolutionStrategy for a potentially better solution to the problem.

基本上,在大多数情况下对每一个配置都是排除传递依赖。这种依赖声明的方式更加明确。它也更准确,因为每个依赖排除规则并不能保证给定的传递依赖不会显示在配置中。例如,某些其他的依赖,并没有任何排除规则,可能会带上那个多余的传递依赖。
Basically, in most of the cases excluding the transitive dependency should be done per configuration. This way the dependency declaration is more explicit. It is also more accurate because a per-dependency exclude rule does not guarantee the given transitive dependency does not show up in the configuration. For example, some other dependency, which does not have any exclude rules, might pull in that unwanted transitive dependency.

其他相关依赖关系排除的示例,可以参考 ModuleDependencyDependencyHandler
Other examples of the dependency exclusions can be found in the reference for ModuleDependency or DependencyHandler.

50.4.8. 可选属性

50.4.8. Optional attributes

一个依赖的所有属性都是可选的,除了 name。这取决于仓库类型,这些信息实际上需要用于在仓库中找到这个依赖。请参阅 50.6 节,“仓库”。例如,如果你使用 Maven 仓库,你需要定义group,name 和 version。如果你使用文件系统仓库,你可能只需要 name 或 name 和 version。
All attributes for a dependency are optional, except the name. It depends on the repository type, which information is need for actually finding the dependencies in the repository. See Section 50.6, “Repositories”. If you work for example with Maven repositories, you need to define the group, name and version. If you work with filesystem repositories you might only need the name or the name and the version.

示例 50.15. 依赖的可选属性 - Example 50.15. Optional attributes of dependencies

build.gradle

dependencies {
    runtime ":junit:4.10", ":testng"
    runtime name: 'testng' 
}

你也可以向一个配置指定依赖 notations 的集合或数组:
You can also assign collections or arrays of dependency notations to a configuration:

示例 50.16. 依赖的集合和数组 - Example 50.16. Collections and arrays of dependencies

build.gradle

List groovy = ["org.codehaus.groovy:groovy-all:2.2.0@jar",
               "commons-cli:commons-cli:1.0@jar",
               "org.apache.ant:ant:1.9.3@jar"]
List hibernate = ['org.hibernate:hibernate:3.0.5@jar', 'somegroup:someorg:1.0@jar']
dependencies {
    runtime groovy, hibernate
}

50.4.9. 依赖配置

50.4.9. Dependency configurations

在 Gradle ,一个依赖可以有不同的配置 (就像你的项目可以有不同的配置)。如果你不显式指定任何东西,Gradle 会使用依赖的默认配置。对于 Maven 存储库的依赖,至少默认配置是唯一可用的一个。如果你使用 Ivy 存储库,并且想要为你的依赖定义一个非默认配置,就要使用 map 标记法并且声明:
In Gradle a dependency can have different configurations (as your project can have different configurations). If you don't specify anything explicitly, Gradle uses the default configuration of the dependency. For dependencies from a Maven repository, the default configuration is the only available one anyway. If you work with Ivy repositories and want to declare a non-default configuration for your dependency you have to use the map notation and declare:

示例 50.17. 依赖配置 - Example 50.17. Dependency configurations

build.gradle

dependencies {
    runtime group: 'org.somegroup', name: 'somedependency', version: '1.0', configuration: 'someConfiguration'
}

同样的项目依赖,你需要声明:
To do the same for project dependencies you need to declare:

示例 50.18. 项目的依赖配置 - Example 50.18. Dependency configurations for project

build.gradle

dependencies {
    compile project(path: ':api', configuration: 'spi')
}

50.4.10. 依赖报告

50.4.10. Dependency reports

你可以从命令行生成依赖报告 (参阅 第11.6.4节,“列出项目依赖”)。通过使用 Project report 插件(参阅 第 41 章, Project Report 插件),在构建中可以创建一个这样的报告。
You can generate dependency reports from the command line (see Section 11.6.4, “Listing project dependencies”). With the help of the Project report plugin (see Chapter 41, The Project Report Plugin) such a report can be created by your build.

从 Gradle 1.2 起,有一个新的编程 API 用于访问解析的依赖信息。依赖报告(见前面一段)正是使用此 API。这个 API 可以让你查看解析的依赖图,并提供有关依赖的信息。在未来的版本,这个API 将提供更多有关解析结果的详细信息。关于这个 API 的更多信息,请参考 ResolvableDependencies.getResolutionResult()上的文档。ResolutionResult API的可能用法:
Since Gradle 1.2 there is also a new programmatic API to access the resolved dependency information. The dependency reports (see the previous paragraph) are using this API under the covers. The API lets you to walk the resolved dependency graph and provides information about the dependencies. With the coming releases the API will grow to provide more information about the resolution result. For more information about the API please refer to the javadocs on ResolvableDependencies.getResolutionResult(). Potential usages of the ResolutionResult API:

  • 创建高级的依赖报告,以适应你的用例。
    Creation of advanced dependency reports tailored to your use case.
  • 启用使构建逻辑基于依赖树的内容来决定。
    Enabling the build logic to make decisions based on the content of the dependency graph.

50.5. 使用依赖

50.5. Working with dependencies

下面的示例我们使用以下依赖设置:
For the examples below we have the following dependencies setup:

示例 50.19. Configuration.copy - Example 50.19. Configuration.copy

build.gradle

configurations {
    sealife
    alllife
}

dependencies {
    sealife "sea.mammals:orca:1.0", "sea.fish:shark:1.0", "sea.fish:tuna:1.0"
    alllife configurations.sealife
    alllife "air.birds:albatros:1.0"
}

这些依赖有以下的传递依赖:
The dependencies have the following transitive dependencies:

shark-1.0 -> seal-2.0, tuna-1.0

orca-1.0 -> seal-1.0

tuna-1.0 -> herring-1.0

你可以使用配置来访问它们的声明依赖或其中一个子集:
You can use the configuration to access the declared dependencies or a subset of those:

示例 50.20. 访问声明依赖 - Example 50.20. Accessing declared dependencies

build.gradle

task dependencies << {
    configurations.alllife.dependencies.each { dep -> println dep.name }
    println()
    configurations.alllife.allDependencies.each { dep -> println dep.name }
    println()
    configurations.alllife.allDependencies.findAll { dep -> dep.name != 'orca' }.each { dep -> println dep.name }
}

gradle -q dependencies的输出结果
Output of gradle -q dependencies

> gradle -q dependencies
albatros

albatros
orca
shark
tuna

albatros
shark
tuna

dependencies返回只明确属于配置的依赖。allDependencies包括了扩展配置的依赖。
dependencies returns only the dependencies belonging explicitly to the configuration. allDependencies includes the dependencies from extended configurations.

要获得配置依赖的library文件,你可以这样:
To get the library files of the configuration dependencies you can do:

示例 50.21. Configuration.files - Example 50.21. Configuration.files

build.gradle

task allFiles << {
    configurations.sealife.files.each { file ->
        println file.name
    }
}

gradle -q allFiles的输出结果
Output of gradle -q allFiles

> gradle -q allFiles
orca-1.0.jar
shark-1.0.jar
tuna-1.0.jar
herring-1.0.jar
seal-2.0.jar

有时你想要配置依赖的某个子集(例如单个依赖)的 library 文件。
Sometimes you want the library files of a subset of the configuration dependencies (e.g. of a single dependency).

示例 50.22. 指定的 Configuration.files - Example 50.22. Configuration.files with spec

build.gradle

task files << {
    configurations.sealife.files { dep -> dep.name == 'orca' }.each { file ->
        println file.name
    }
}

gradle -q files的输出结果
Output of gradle -q files

> gradle -q files
orca-1.0.jar
seal-2.0.jar

Configuration.files方法总是获取整个配置的所有 artifacts。然后,由指定的依赖筛选获取的文件。正如你在示例中所看到的,传递依赖都被包括在内。
The Configuration.files method always retrieves all artifacts of the whole configuration. It then filters the retrieved files by specified dependencies. As you can see in the example, transitive dependencies are included.

你还可以复制配置。你可以选择指定只复制原始配置里的一个子集的依赖。复制的方法有两种。copy方法只复制明确属于配置的依赖。copyRecursive方法将复制所有依赖,包括扩展配置的依赖。
You can also copy a configuration. You can optionally specify that only a subset of dependencies from the original configuration should be copied. The copying methods come in two flavors. The copy method copies only the dependencies belonging explicitly to the configuration. The copyRecursive method copies all the dependencies, including the dependencies from extended configurations.

示例 50.23. Configuration.copy - Example 50.23. Configuration.copy

build.gradle

task copy << {
    configurations.alllife.copyRecursive { dep -> dep.name != 'orca' }.allDependencies.each { dep ->
        println dep.name
    }
    println()
    configurations.alllife.copy().allDependencies.each { dep ->
        println dep.name
    }
}

gradle -q copy 的输出结果
Output of gradle -q copy

> gradle -q copy
albatros
shark
tuna

albatros

要重点注意,复制的配置所返回的文件,往往并不总是与原始配置的依赖子集所返回的文件一样。在子集的依赖和不属于子集的依赖之间,存在版本冲突的情况下,解析的结果可能会有所不同。
It is important to note that the returned files of the copied configuration are often but not always the same than the returned files of the dependency subset of the original configuration. In case of version conflicts between dependencies of the subset and dependencies not belonging to the subset the resolve result might be different.

示例 50.24. Configuration.copy 与 Configuration.files - Example 50.24. Configuration.copy vs. Configuration.files

build.gradle

task copyVsFiles << {
    configurations.sealife.copyRecursive { dep -> dep.name == 'orca' }.each { file ->
        println file.name
    }
    println()
    configurations.sealife.files { dep -> dep.name == 'orca' }.each { file ->
        println file.name
    }
}

gradle -q copyVsFiles的输出结果
Output of gradle -q copyVsFiles

> gradle -q copyVsFiles
orca-1.0.jar
seal-1.0.jar

orca-1.0.jar
seal-2.0.jar

在上面的例子中 orca 依赖 seal-1.0shark 依赖于 seal-2.0。原始配置因此有版本冲突,所以被解析为更新的 seal-2.0 版本。files 方法因此返回 seal-2.0 作为 orca的传递依赖。复制的配置只有 orca 一个依赖,因此没有版本冲突,seal-1.0 作为传递依赖被返回。
In the example above, orca has a dependency on seal-1.0 whereas shark has a dependency onseal-2.0. The original configuration has therefore a version conflict which is resolved to the newer seal-2.0 version. The files method therefore returns seal-2.0 as a transitive dependency oforca. The copied configuration only has orca as a dependency and therefore there is no version conflict and seal-1.0 is returned as a transitive dependency.

一旦一个配置被解析,那它就是不可变的了。如果去修改它的状态,或者是它的某个依赖的状态,将会引发一个异常。你可以永远复制一个解析了的配置。这个复制的配置处于未解析的状态,并且可以被刷新解析。
Once a configuration is resolved it is immutable. Changing its state or the state of one of its dependencies will cause an exception. You can always copy a resolved configuration. The copied configuration is in the unresolved state and can be freshly resolved.

想了解更多关于这个配置类的API,可以参阅它的 API 文档:Configuration.
To learn more about the API of the configuration class see the API documentation: Configuration.

50.6. 仓库

50.6. Repositories

Gradle 仓库管理,基于 Apache Ivy,为你提供了有关仓库布局和获取策略的许多自由。另外,Gradle 提供了各种方便的方法来添加预配置的仓库。
Gradle repository management, based on Apache Ivy, gives you a lot of freedom regarding repository layout and retrieval policies. Additionally Gradle provides various convenience method to add pre-configured repositories.

您可以配置任意数量的仓库,每一个都会被Gradle 独立处理。如果 Gradle 在特定仓库中查找模块描述符,它将尝试从同一仓库中下载该模块的所有 artifacts。虽然模块的元数据和模块 artifacts 必须位于同一仓库,但也有可能单个仓库有多个 Url,给多个位置去搜索元数据文件和 jar 文件。
You may configure any number of repositories, each of which is treated independently by Gradle. If Gradle finds a module descriptor in a particular repository, it will attempt to download all of the artifacts for that module from the same repository. Although module meta-data and module artifacts must be located in the same repository, it is possible to compose a single repository of multiple URLs, giving multiple locations to search for meta-data files and jar files.

有几种不同类型的存储库可以声明:
There are several different types of repositories you can declare:

表 50.2. 仓库类型 - Table 50.2. Repository types

类型
Type
描述
Description
Maven 中央仓库
Maven central repository
一个会在 Maven 中央仓中查找依赖的预配置仓库。
A pre-configured repository that looks for dependencies in Maven Central.
Maven JCenter 仓库
Maven JCenter repository
一个会在 Bintray 的 Jcenter 查找依赖的预配置仓库。
A pre-configured repository that looks for dependencies in Bintray's JCenter.
Maven 本地仓库
Maven local repository
一个会在本地 Maven 仓库中查找依赖的预配置仓库。
A pre-configured repository that looks for dependencies in the local Maven repository.
Maven 仓库
Maven repository
一个 Maven 仓库。可以位于本地文件系统上,或在某个远程的位置。
A Maven repository. Can be located on the local filesystem or at some remote location.
Ivy 仓库
Ivy repository
一个 Ivy 仓库可以位于本地文件系统上,或在某个远程的位置。
An Ivy repository. Can be located on the local filesystem or at some remote location.
Flat 目录仓库
Flat directory repository
一个在本地文件系统上的简单的仓库。不支持任何元数据格式。
A simple repository on the local filesystem. Does not support any meta-data formats.

50.6.1. Maven 中央仓库

50.6.1. Maven central repository

若要添加中央 Maven 2 仓库(http://repo1.maven.org/maven2),只需添加下面的代码到你的构建脚本中:
To add the central Maven 2 repository (http://repo1.maven.org/maven2) simply add this to your build script:

示例 50.25. 添加 Maven 中央仓库 - Example 50.25. Adding central Maven repository

build.gradle

repositories {
    mavenCentral()
}

现在 Gradle 将会在此仓库中查找你的依赖。
Now Gradle will look for your dependencies in this repository.

50.6.2. Maven JCenter 仓库

50.6.2. Maven JCenter repository

BintrayJCenter 是所有流行的 Maven OSS artifacts 的up-to-date 集合,包括直接发布到 Bintray 的 artifacts。
Bintray's JCenter is an up-to-date collection of all popular Maven OSS artifacts, including artifacts published directly to Bintray.

若要添加 JCenter Maven 仓库(http://jcenter.bintray.com),只需添加下面的内容到你的构建脚本中:
To add the JCenter Maven repository (http://jcenter.bintray.com) simply add this to your build script:

示例 50.26. 添加 Bintray Jcenter Maven 仓库 - Example 50.26. Adding Bintray's JCenter Maven repository

build.gradle

repositories {
    jcenter()
}

现在 Gradle 将会在 JCenter 仓库中查找你的依赖。
Now Gradle will look for your dependencies in the JCenter repository.

50.6.3. 本地 Maven 仓库

50.6.3. Local Maven repository

你可以这样把本地的 Maven 缓存作为仓库使用:
To use the local Maven cache as a repository you can do:

示例 50.27. 添加本地 Maven 缓存作为仓库: - Example 50.27. Adding the local Maven cache as a repository

build.gradle

repositories {
    mavenLocal()
}

Gradle 使用与 Maven 相同的逻辑来标识你本地的 Maven 缓存的位置。如果在settings.xml中定义一个本地仓库的位置,那么这个位置将会被使用。在USER_HOME/.m2settings.xml 比在 M2_HOME/confsettings.xml优先。如果没有settings.xml可用,Gradle 将使用默认的位置USER_HOME/.m2/repository
Gradle uses the same logic as Maven to identify the location of your local Maven cache. If a local repository location is defined in a settings.xml, this location will be used. The settings.xml in USER_HOME/.m2 takes precedence over the settings.xml in M2_HOME/conf. If no settings.xml is available, Gradle uses the default location USER_HOME/.m2/repository.

50.6.4. Maven 仓库

50.6.4. Maven repositories

要添加一个自定义的 Maven 仓库,你可以如下操作:
For adding a custom Maven repository you can do:

示例 50.28. 添加一个自定义的 Maven 仓库 - Example 50.28. Adding custom Maven repository

build.gradle

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

有时候,一个仓库会出现 POM 文件发布在一个地方,而 JAR 文件和其他构件发布在另一个地方。要定义一个这样的仓库,你可以这样:
Sometimes a repository will have the POMs published to one location, and the JARs and other artifacts published at another location. To define such a repository, you can do:

示例 50.29. 为 JAR 文件添加额外的 Maven 仓库 - Example 50.29. Adding additional Maven repositories for JAR files

build.gradle

repositories {
    maven {
        // Look for POMs and artifacts, such as JARs, here
        url "http://repo2.mycompany.com/maven2"
        // Look for artifacts here if not found at the above location
        artifactUrls "http://repo.mycompany.com/jars"
        artifactUrls "http://repo.mycompany.com/jars2"
    }
}

Gradle 将会在第一个URL中查找 POM 和 JAR 文件。如果那里找不到 JAR,就会用 artifact URLs 来查找 JAR 文件。
Gradle will look at the first URL for the POM and the JAR. If the JAR can't be found there, the artifact URLs are used to look for JARs.

50.6.4.1. 访问密码保护的 Maven 仓库

50.6.4.1. Accessing password protected Maven repositories

要访问一个使用基本的身份验证的 Maven 仓库,当你在定义该仓库时要指定使用的用户名和密码:
To access a Maven repository which uses basic authentication, you specify the username and password to use when you define the repository:

示例 50.30. 访问密码保护的 Maven 仓库 - Example 50.30. Accessing password protected Maven repository

build.gradle

repositories {
    maven {
        credentials {
            username 'user'
            password 'password'
        }
        url "http://repo.mycompany.com/maven2"
    }
}

最好是把你的用户名和密码写在gradle.properties中,而不是直接写在构建文件中。
It is advisable to keep your username and password in gradle.properties rather than directly in the build file.

50.6.5. 平面的目录仓库

50.6.5. Flat directory repository

如果你想要把一个(平面)文件系统目录作为仓库使用,只需输入:
If you want to use a (flat) filesystem directory as a repository, simply type:

示例 50.31. 平面仓库的解决 - Example 50.31. Flat repository resolver

build.gradle

repositories {
    flatDir {
        dirs 'lib'
    }
    flatDir {
        dirs 'lib1', 'lib2'
    }
}

这将会添加一些用于查找依赖的仓库,它会在一个或多个目录中寻找。如果你只使用平面目录解析器,那么你不需要去设置一个依赖的所有属性。请参阅 第50.4.8 节,“可选属性”
This adds repositories which look into one or more directories for finding dependencies. If you only work with flat directory resolvers you don't need to set all attributes of a dependency. See Section 50.4.8, “Optional attributes”

50.6.6. Ivy 存储库

50.6.6. Ivy repositories

使用一个标准布局的 Ivy 存储库:
To use an Ivy repository with a standard layout:

示例 50.32. Ivy存储库 - Example 50.32. Ivy repository

build.gradle

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

详细信息请参阅IvyArtifactRepository
See IvyArtifactRepository for details.

50.6.6.1. 为一个 Ivy 存储库定义自定义的模式

50.6.6.1. Defining custom patterns for an Ivy repository

若要定义非标准布局的 Ivy 仓库,你可以定义一个仓库模式布局:
To define an Ivy repository with a non-standard layout, you can define a pattern layout for the repository:

示例 50.33. Ivy 仓库模式布局 - Example 50.33. Ivy repository with pattern layout

build.gradle

repositories {
    ivy {
        url "http://repo.mycompany.com/repo"
        layout "pattern", {
            artifact "[module]/[revision]/[type]/[artifact].[ext]"
        }
    }
}

50.6.6.2. 使用 Maven 兼容布局的 Ivy 仓库

50.6.6.2. Ivy repository with Maven compatible layout

作为可选的功能,一个使用模式布局的仓库可以有它自己的以Maven 风格奠定的“组织”部分,该部分使用斜杠替换点作为分隔符。例如,组织my.company将表示为my/company
Optionally, a repository with pattern layout can have its 'organisation' part laid out in Maven style, with forward slashes replacing dots as separators. For example, the organisation my.company would then be represented as my/company.

示例50.34. 使用 Maven 兼容布局的 Ivy 仓库 - Example 50.34. Ivy repository with Maven compatible layout

build.gradle

repositories {
    ivy {
        url "http://repo.mycompany.com/repo"
        layout "pattern", {
            artifact "[organisation]/[module]/[revision]/[artifact]-[revision].[ext]"
            m2compatible = true
        }
    }
}

50.6.6.3. 为一个 Ivy 仓库定义不同的 artifact 和 Ivy 文件位置

50.6.6.3. Defining different artifact and Ivy file locations for an Ivy repository

若要定义一个从不同的位置获取 Ivy 文件和 artifacts 的 Ivy 仓库,您可以使用模式布局,每个单独的模式用于定位到 Ivy 文件和 artifacts:
To define an Ivy repository which fetches Ivy files and artifacts from different locations, you can use the pattern layout with separate patterns to use to locate the Ivy files and artifacts:

示例 50.35. 自定义模式的 Ivy 仓库 - Example 50.35. Ivy repository with custom patterns

build.gradle

repositories {
    ivy {
        url "http://repo.mycompany.com/repo"
        layout "pattern", {
            artifact "3rd-party-artifacts/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]"
            artifact "company-artifacts/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]"
            ivy "ivy-files/[organisation]/[module]/[revision]/ivy.xml"
        }
    }
}

每个artifactivy都指定了一个仓库,添加一个额外的的模式来使用。这些模式以定义它们的顺序来使用。
Each artifact or ivy specified for a repository adds an additional pattern to use. The patterns are used in the order that they are defined.

50.6.6.4. 访问密码保护的 Ivy 仓库

50.6.6.4. Accessing password protected Ivy repositories

要访问一个使用基本的身份验证的 Ivy 仓库,当你在定义该仓库时要指定使用的用户名和密码:
To access an Ivy repository which uses basic authentication, you specify the username and password to use when you define the repository:

示例 50.36. Ivy存储库 - Example 50.36. Ivy repository

build.gradle

repositories {
    ivy {
        url 'http://repo.mycompany.com'
        credentials {
            username 'user'
            password 'password'
        }
    }
}

50.6.7. 使用仓库

50.6.7. Working with repositories

若要访问一个仓库:
To access a repository:

示例 50.37. 访问一个仓库: - Example 50.37. Accessing a repository

build.gradle

println repositories.localRepository.name
    println repositories['localRepository'].name

要配置一个仓库:
To configure a repository:

示例 50.38. 仓库配置 - Example 50.38. Configuration of a repository

build.gradle

repositories {
    flatDir {
        name 'localRepository'
    }
}
repositories {
    localRepository {
        dirs 'lib'
    }
}
repositories.localRepository {
    dirs 'lib'
}

50.6.8. 更多关于 Ivy 解析器的信息

50.6.8. More about Ivy resolvers

Gradle由于 Ivy 在它的 hood 之下,对仓库非常灵活。
Gradle, thanks to Ivy under its hood, is extremely flexible regarding repositories:

  • 对于与仓库通信的协议,有很多的选项(比如文件系统,http, ssh……)


    There are many options for the protocol to communicate with the repository (e.g. filesystem, http, ssh, ...)

  • 每个仓库都可以有其自己的布局。


    Each repository can have its own layout.

比方说,你可以声明一个junit:junit:3.8.2库的依赖。现在 Gradle 是如何发现它在存储库中的?某种程度上依赖信息必须映射到一个路径上。相比于固定路径的 Maven,使用 Gradle 你可以定义一个模式,该模式定义了路径的样子。这里有一些例子:[16]
Let's say, you declare a dependency on the junit:junit:3.8.2 library. Now how does Gradle find it in the repositories? Somehow the dependency information has to be mapped to a path. In contrast to Maven, where this path is fixed, with Gradle you can define a pattern that defines what the path will look like. Here are some examples: [16]

// Maven2 layout (if a repository is marked as Maven2 compatible, the organization (group) is split into subfolders according to the dots.)
someroot/[organisation]/[module]/[revision]/[module]-[revision].[ext]

// Typical layout for an Ivy repository (the organization is not split into subfolder)
someroot/[organisation]/[module]/[revision]/[type]s/[artifact].[ext]

// Simple layout (the organization is not used, no nested folders.)
someroot/[artifact]-[revision].[ext]

要添加任何一种仓库 (你可以很简单地编写你自己的) ,你可以:
To add any kind of repository (you can pretty easy write your own ones) you can do:

示例 50.39. 自定义仓库的定义 - Example 50.39. Definition of a custom repository

build.gradle

repositories {
    ivy {
        ivyPattern "$projectDir/repo/[organisation]/[module]-ivy-[revision].xml"
        artifactPattern "$projectDir/repo/[organisation]/[module]-[revision](-[classifier]).[ext]"
    }
}

其中由 Ivy (也因此由 Gradle )提供解析器的,它的概述可以在这里找到。通过Gradle,你只是不用通过XML来配置它们,而是通过它们的API。
An overview of which Resolvers are offered by Ivy and thus also by Gradle can be found here. With Gradle you just don't configure them via XML but directly via their API.

50.7. 依赖解析的工作原理

50.7. How dependency resolution works

Gradle 将获取你的依赖声明和仓库定义,并通过一个称为依赖项解析的过程尝试下载所有依赖项。下面是这个过程的工作原理的简要概述。
Gradle takes your dependency declarations and repository definitions and attempts to download all of your dependencies by a process called dependency resolution. Below is a brief outline of how this process works.

  • 给出所需的依赖项,Gradle 首先尝试为该依赖解析模块。每个仓库按顺序进行检查,首先查找指示该模块存在的模块描述符文件(POM 或 Ivy 文件)。如果没有找到模块描述符,Gradle 将搜索表示模块存在于存储库中的主要模块 artifact文件。

    • 如果依赖被声明为一个动态版本(像1.+),Gradle 将会把它解析到在仓库中的最新的可用的静态版本(如1.2)。对于 Maven 仓库,是通过maven metadata.xml文件来实现,而对于 Ivy 存储库,则是通过目录列表。

    • 如果模块描述符是一个具有的父 POM 文件声明的 POM 文件,Gradle 将以递归方式尝试为该 POM 文件解析每个父模块。


    Given a required dependency, Gradle first attempts to resolve the module for that dependency. Each repository is inspected in order, searching first for a module descriptor file (POM or Ivy file) that indicates the presence of that module. If no module descriptor is found, Gradle will search for the presence of the primary module artifact file indicating that the module exists in the repository.

    • If the dependency is declared as a dynamic version (like 1.+), Gradle will resolve this to the newest available static version (like 1.2) in the repository. For Maven repositories, this is done using the maven-metadata.xml file, while for Ivy repositories this is done by directory listing.

    • If the module descriptor is a POM file that has a parent POM declared, Gradle will recursively attempt to resolve each of the parent modules for the POM.

  • 一旦已为该模块检查了每个仓库,Gradle 将会选择使用“最好”的一个。它使用以下标准来完成:

    • 对于动态版本,“高”的静态版本优于“低”的版本。
    • 由模块描述符文件(Ivy或 POM 文件)声明的文件优于只有一个artifact 文件的模块。
    • 前面的仓库的模块优于后面的仓库的模块。

    当依赖由一个静态版本来声明,并且在仓库中找到模块描述符文件时,将不会再继续搜索后面的仓库,这个过程的其余部分是短路的。


    Once each repository has been inspected for the module, Gradle will choose the 'best' one to use. This is done using the following criteria:

    • For a dynamic version, a 'higher' static version is preferred over a 'lower' version.
    • Modules declared by a module descriptor file (Ivy or POM file) are preferred over modules that have an artifact file only.
    • Modules from earlier repositories are preferred over modules in later repositories.

    When the dependency is declared by a static version and a module descriptor file is found in a repository, there is no need to continue searching later repositories and the remainder of the process is short-circuited.

  • 然后这个模块的所有artifact将从上面的过程所选择的 同一个仓库 中请求。


    All of the artifacts for the module are then requested from the same repository that was chosen in the process above.

50.8. 微调依赖解析过程

50.8. Fine-tuning the dependency resolution process

在大多数情况下,Gradle 的默认依赖管理将会在你的构建中按你所想的解析依赖关系。然而,在某些情况下,会有必要调整依赖解析,以确保你的构建能得到正确的依赖关系。
In most cases, Gradle's default dependency management will resolve the dependencies that you want in your build. In some cases, however, it can be necessary to tweak dependency resolution to ensure that your build receives exactly the right dependencies.

有许多种方式都可以影响到Gradle解析依赖。
There are a number of ways that you can influence how Gradle resolves dependencies.

50.8.1. 强制一个特定模块的版本

50.8.1. Forcing a particular module version

强制一个模块的版本,是告诉 Gradle 对于指定的依赖(不管是否传递依赖),始终使用一个特定的版本,而覆盖在发布的模块描述符中所指定的任何版本。当解决版本冲突时,这可能非常有用——有关详细信息请参阅第 50.2.3 节,“解决版本冲突”
Forcing a module version tells Gradle to always use a specific version for given dependency (transitive or not), overriding any version specified in a published module descriptor. This can be very useful when tackling version conflicts - for more information see Section 50.2.3, “Resolve version conflicts”.

强制版本也可以用于处理传递依赖所带来的流氓元数据。如果传递依赖有质量较差的元数据,导致了依赖解析时的问题时,你可以强制 Gradle 对于这一依赖使用一个较新的,固定的版本。有关示例,请参见ResolutionStrategy。请注意,“依赖解析规则”(见下文),提供了一种更强大的机制,来取代一个损坏的模块依赖。请参阅50.8.2.3 节,“黑名单替换指定版本”
Force versions can also be used to deal with rogue metadata of transitive dependencies. If a transitive dependency has poor quality metadata that leads to problems at dependency resolution time, you can force Gradle to use a newer, fixed version of this dependency. For an example, see ResolutionStrategy. Note that 'dependency resolve rules' (outlined below) provide a more powerful mechanism for replacing a broken module dependency. See Section 50.8.2.3, “Blacklisting a particular version with a replacement”.

50.8.2. 使用依赖解析规则

50.8.2. Using dependency resolve rules

一个依赖解析规则为每一个解析依赖执行,并提供功能强大的 api 用于在解析依赖之前处理这个依赖的请求。此功能还在孵化中,但目前提供了对于一个请求的依赖更改组、 名称及版本的功能,允许在解析过程中,把一个依赖替换为另一个完全不同的模块。
A dependency resolve rule is executed for each resolved dependency, and offers a powerful api for manipulating a requested dependency prior to that dependency being resolved. This feature is incubating, but currently offers the ability to change the group, name and/or version of a requested dependency, allowing a dependency to be substituted with a completely different module during resolution.

依赖解析规则提供了一种非常强大的方式来控制依赖解析过程,并可以用于实现在依赖管理中各种高级模式的排序。下面将概述其中的某些模式。更多的信息和代码示例请参阅ResolutionStrategy
Dependency resolve rules provide a very powerful way to control the dependency resolution process, and can be used to implement all sorts of advanced patterns in dependency management. Some of these patterns are outlined below. For more information and code samples see ResolutionStrategy.

50.8.2.1. 模块化可发布的单位

50.8.2.1. Modelling releaseable units

通常一个组织会使用一个版本发布一组库;这些库将在一起构建,测试以及发布。这些库形成一个“可发布的单位”,被设计并打算作为一个整体使用。而一起使用来自不同的可发布单位的库,也不会有意义。
Often an organisation publishes a set of libraries with a single version; where the libraries are built, tested and published together. These libraries form a 'releasable unit', designed and intended to be used as a whole. It does not make sense to use libraries from different releasable units together.

但传递依赖解析会很容易破坏这种协议。举个例子:
But it is easy for transitive dependency resolution to violate this contract. For example:

  • module-a 依赖于 releasable-unit:part-one:1.0
    module-a depends on releasable-unit:part-one:1.0
  • module-a 依赖于 releasable-unit:part-one:1.0
    module-b depends on releasable-unit:part-two:1.1

一个依赖于module-amodule-b的构建,将在可发布单位内获得这个库的不同版本。
A build depending on both module-a and module-b will obtain different versions of libraries within the releasable unit.

依赖解析规则使你能够在构建中强制指定可发布的单位。想象一下,一个可发布的单位,由有“org.gradle” 组的所有库定义。我们可以强制所有这些库使用一致的版本:
Dependency resolve rules give you the power to enforce releasable units in your build. Imagine a releasable unit defined by all libraries that have 'org.gradle' group. We can force all of these libraries to use a consistent version:

示例 50.40. 强制一个组的所有库使用一致的版本 - Example 50.40. Forcing consistent version for a group of libraries

build.gradle

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        if (details.requested.group == 'org.gradle') {
            details.useVersion '1.4'
        }
    }
}


50.8.2.2. 实现一个自定义的版本方案

50.8.2.2. Implement a custom versioning scheme

在一些企业的环境中,可以声明在 gradle 构建中的模块版本列表,是在外部维护和审核的。依赖解析规则提供了这种模式的整洁的实现:
In some corporate environments, the list of module versions that can be declared in gradle builds is maintained and audited externally. Dependency resolve rules provide a neat implementation of this pattern:

  • 在构建脚本中,开发人员使用模块组与名称声明依赖,但使用占位符版本,例如:“default”。
    In the build script, the developer declares dependencies with the module group and name, but uses a placeholder version, for example: 'default'.
  • 这个“default”版本通过一个依赖解析规则被解析为一个特定的版本,这个规则将在一个核准模块的公司中查找该版本。
    The 'default' version is resolved to a specific version via a dependency resolve rule, which looks up the version in a corporate catalog of approved modules.

该规则实现可以整齐地封装在一个公司的插件中,并在组织内和所有构建共享。
This rule implementation can be neatly encapsulated in a corporate plugin, and shared across all builds within the organisation.

示例 50.41. 使用自定义的版本方案 - Example 50.41. Using a custom versioning scheme

build.gradle

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        if (details.requested.version == 'default') {
            def version = findDefaultVersionInCatalog(details.requested.group, details.requested.name)
            details.useVersion version
        }
    }
}

def findDefaultVersionInCatalog(String group, String name) {
    //some custom logic that resolves the default version into a specific version
    "1.0"
}


50.8.2.3. 黑名单替换特定版本

50.8.2.3. Blacklisting a particular version with a replacement

依赖解析规则提供了一个机制,用于把一个依赖的指定版本列入黑名单,并提供一个替代的版本。如果某个依赖的版本坏了,并且不应该被使用,这个机制将非常有用。一个依赖解析规则将会使这个版本被替换为一个已知的好的版本。一个坏的模块的例子是,在一个库上声明的一个依赖无法在任何公共仓库中找到,但为什么不能使用一个特定的模块版本,而更希望要另一个版本,还有很多其他原因。
Dependency resolve rules provide a mechanism for blacklisting a particular version of a dependency and providing a replacement version. This can be useful if a certain dependency version is broken and should not be used, where a dependency resolve rule causes this version to be replaced with a known good version. One example of a broken module is one that declares a dependency on a library that cannot be found in any of the public repositories, but there are many other reasons why a particular module version is unwanted and a different version is preferred.

在下面的示例中,想象版本1.2.1包含了重要的修复程序,并应始终优先于1.2使用。提供的规则将强制执行:在任何时间遇到了1.2版本,都将会替换为1.2.1。注意,这与上面描述的强制使用一个版本不同,这个模块的其他版本将不受影响。这意味着,如果这个版本也因依赖传递被获取到,“使用最新”的冲突解决策略仍然会选择 1.3 版本。
In example below, imagine that version 1.2.1 contains important fixes and should always be used in preference to 1.2. The rule provided will enforce just this: any time version 1.2 is encountered it will be replaced with 1.2.1. Note that this is different from a forced version as described above, in that any other versions of this module would not be affected. This means that the 'newest' conflict resolution strategy would still select version 1.3 if this version was also pulled transitively.

示例 50.42. 黑名单替换特定版本 - Example 50.42. Blacklisting a version with a replacement

build.gradle

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        if (details.requested.group == 'org.software' && details.requested.name == 'some-library' && details.requested.version == '1.2') {
            //prefer different version which contains some necessary fixes
            details.useVersion '1.2.1'
        }
    }
}


50.8.2.4. 使用一个兼容模块替换一个依赖模块

50.8.2.4. Substituting a dependency module with a compatible replacement

有时一个完全不同的模块可以作为请求的模块依赖的替代者。示例包括,使用“groovy”来代替“groovy-all”,或者使用“log4j-over-slf4j”来代替“log4j”。从 Gradle 1.5 开始,你可以使用依赖解析规则来进行这些替换:
At times a completely different module can serve as a replacement for a requested module dependency. Examples include using 'groovy' in place of 'groovy-all', or using 'log4j-over-slf4j' instead of 'log4j'. Starting with Gradle 1.5 you can make these substitutions using dependency resolve rules:

示例 50.43. 在解析中更改依赖组及名称 - Example 50.43. Changing dependency group and/or name at the resolution

build.gradle

configurations.all {
    resolutionStrategy.eachDependency { DependencyResolveDetails details ->
        if (details.requested.name == 'groovy-all') {
            //prefer 'groovy' over 'groovy-all':
            details.useTarget group: details.requested.group, name: 'groovy', version: details.requested.version
        }
        if (details.requested.name == 'log4j') {
            //prefer 'log4j-over-slf4j' over 'log4j', with fixed version:
            details.useTarget "org.slf4j:log4j-over-slf4j:1.7.5"
        }
    }
}


50.8.3. 启用 Ivy 动态解析模式

50.8.3. Enabling Ivy dynamic resolve mode

Gradle 的Ivy 仓库实现支持相当于 Ivy 的动态解析的模式。通常情况下,Gradle 将rev属性用于在ivy.xml文件中包含的每个依赖定义。在动态解析模式中,Gradle 将优先使用revConstraint属性来代替rev属性,用于一个给定的依赖定义。如果不存在revConstraint属性,则使用rev属性。
Gradle's Ivy repository implementations support the equivalent to Ivy's dynamic resolve mode. Normally, Gradle will use the rev attribute for each dependency definition included in an ivy.xml file. In dynamic resolve mode, Gradle will instead prefer the revConstraint attribute over the rev attribute for a given dependency definition. If the revConstraint attribute is not present, the rev attribute is used instead.

若要启用动态解析模式,你需要在仓库定义进行合适的设置。下面展示了几个例子。注意,动态解析模式只对 Gradle 的 Ivy 仓库有效。它不能用于 Maven 仓库,或自定义的 Ivy DependencyResolver实现。
To enable dynamic resolve mode, you need to set the appropriate option on the repository definition. A couple of examples are shown below. Note that dynamic resolve mode is only available for Gradle's Ivy repositories. It is not available for Maven repositories, or custom Ivy DependencyResolver implementations.

示例 50.44. 启用动态解析模式 - Example 50.44. Enabling dynamic resolve mode

build.gradle

// Can enable dynamic resolve mode when you define the repository
repositories {
    ivy {
        url "http://repo.mycompany.com/repo"
        resolve.dynamicMode = true
    }
}

// Can use a rule instead to enable (or disable) dynamic resolve mode for all repositories
repositories.withType(IvyArtifactRepository) {
    resolve.dynamicMode = true
}

50.8.4. 组件元数据规则

50.8.4. Component metadata rules

每个模块(也称为组件)都有相关的元数据上,像它的组,名称,版本,依赖,等等。这个元数据通常来源于模块的描述符。元数据规则允许模块的元数据在构建脚本中被操纵。它们在模块描述符下载之后,被所有候选版本之间选择之前生效。这使得元数据成为自定义依赖解析的另一种手段。
Each module (also called component) has metadata associated with it, such as its group, name, version, dependencies, and so on. This metadata typically originates in the module's descriptor. Metadata rules allow certain parts of a module's metadata to be manipulated from within the build script. They take effect after a module's descriptor has been downloaded, but before it has been selected among all candidate versions. This makes metadata rules another instrument for customizing dependency resolution.

其中一个 Gradle 能理解的模块元数据是模块的状态模式。这一概念,也可以从 Ivy 中,随着时间推移,一个模块发展的成熟水平可以得知。默认状态模式,按状态的成熟程度排序,分别是integrationmilestonerelease。除了状态模式以外,模块也有一个(当前) 的状态,这个状态必须是它的状态模式中的值之一。如果没有在(Ivy)描述符中指定,Ivy 模块和 Maven snapshot模块的状态默认为integration ,不是snapshot 的 Maven 模块则默认为release
One piece of module metadata that Gradle understands is a module's status scheme. This concept, also known from Ivy, models the different levels of maturity that a module transitions through over time. The default status scheme, ordered from least to most mature status, is integration, milestone, release. Apart from a status scheme, a module also has a (current) status, which must be one of the values in its status scheme. If not specified in the (Ivy) descriptor, the status defaults to integration for Ivy modules and Maven snapshot modules, and release for Maven modules that aren't snapshots.

一个模块的状态以及状态模式,会在解析 latest 版本选择器时考虑到。具体而言,latest.someStatus 将会解析成有着someStatus 或更成熟状态的最高的模块版本。例如,在适当的位置使用默认的状态模式,latest.integration将选择最高的模块版本,不论其状态(因为integration是成熟度最低的状态),而latest.release将选择release状态的最高模块版本。这里是在代码中的表现:
A module's status and status scheme are taken into consideration when a latest version selector is resolved. Specifically, latest.someStatus will resolve to the highest module version that has status someStatus or a more mature status. For example, with the default status scheme in place, latest.integration will select the highest module version regardless of its status (because integration is the least mature status), whereas latest.release will select the highest module version with status release. Here is what this looks like in code:

示例 50.45,“Latest”版本选择器 - Example 50.45. 'Latest' version selector

build.gradle

dependencies {
    config1 "sea.fish:tuna:latest.integration"
    config2 "sea.fish:tuna:latest.release"
}

task listFish << {
    configurations.config1.each { println it.name }
    println()
    configurations.config2.each { println it.name}
}

gradle -q listFish的输出结果
Output of gradle -q listFish

> gradle -q listFish
tuna-1.5.jar

tuna-1.4.jar

下一个示例演示了基于在一个模块的元数据规则中声明的自定义状态模式的latest选择器:
The next example demonstrates latest selectors based on a custom status scheme declared in a module metadata rule:

示例 50.46. 自定义状态模式 - Example 50.46. Custom status scheme

build.gradle

dependencies {
    config3 "air.birds:albatros:latest.silver"
    components {
        eachComponent { ComponentMetadataDetails details ->
            if (details.id.group == "air.birds") {
                details.statusScheme = ["bronze", "silver", "gold", "platinum"]
            }
        }
    }
}

task listBirds << {
    configurations.config3.each { println it.name }
}

gradle -q listBirds的输出结果
Output of gradle -q listBirds

> gradle -q listBirds
albatros-2.0.jar

50.9. 依赖缓存

50.9. The dependency cache

Gradle 包含了一个高度复杂的依赖缓存机制,该机制力求减少依赖解析中的远程请求,同时努力保证依赖解析结果的正确及可再生性。
Gradle contains a highly sophisticated dependency caching mechanism, which seeks to minimise the number of remote requests made in dependency resolution, while striving to guarantee that the results of dependency resolution are correct and reproducible.

Gradle 依赖缓存包含 2 个主要类型的存储:
The Gradle dependency cache consists of 2 key types of storage:

  • 一个基于文件的下载构件存储,包括像jars这样的二进制文件,以及像 POM 文件以及 Ivy 文件这样的原始下载的元数据。下载的构件的存储路径包括了 SHA1 校验和,意味着 2 个具有相同名称但内容不同的构件可以很容易地被缓存。


    A file-based store of downloaded artifacts, including binaries like jars as well as raw downloaded meta-data like POM files and Ivy files. The storage path for a downloaded artifact includes the SHA1 checksum, meaning that 2 artifacts with the same name but different content can easily be cached.

  • 解析的模块元数据的二进制存储,包括解析动态版本、 模块描述符和构件的结果。


    A binary store of resolved module meta-data, including the results of resolving dynamic versions, module descriptors, and artifacts.

从下载的构件的存储中分享出缓存的元数据,将允许我们使用缓存做一些非常有用的东西,而如果使用一个透明的只有文件的缓存布局则会很困难。
Separating the storage of downloaded artifacts from the cache metadata permits us to do some very powerful things with our cache that would be difficult with a transparent, file-only cache layout.

Gradle 缓存中不允许本地缓存隐藏问题和,以及一直是许多构建工具的挑战的创造神秘及难以调试的行为。这一新行为通过带宽和存储空间的有效途径被实现。在此过程中,Gradle 实现了可靠和可重复的的企业构建。
The Gradle cache does not allow the local cache to hide problems and creating mysterious and difficult to debug behavior that has been a challenge with many build tools. This new behavior is implemented in a bandwidth and storage efficient way. In doing so, Gradle enables reliable and reproducible enterprise builds.

50.9.1. Gradle 依赖缓存的主要特点

50.9.1. Key features of the Gradle dependency cache

50.9.1.1. 单独的元数据缓存

50.9.1.1. Separate metadata cache

Gradle 以二进制格式在元数据缓存中保留了依赖解析的各方面的记录。存储在元数据缓存中的信息包括:
Gradle keeps a record of various aspects of dependency resolution in binary format in the metadata cache. The information stored in the metadata cache includes:

  • 解析一个动态版本(例如1.+)到一个具体的版本(例如1.2)的结果。
    The result of resolving a dynamic version (e.g. 1.+) to a concrete version (e.g. 1.2).
  • 对于特定模块的解析后的模块元数据,包括模块构件和模块依赖。
    The resolved module metadata for a particular module, including module artifacts and module dependencies.
  • 对于特定构件的解析后的构件元数据,包括指向下载的构件工件的信息。
    The resolved artifact metadata for a particular artifact, including a pointer to the downloaded artifact file.
  • 在特定的仓库中缺少的特定模块或工件,避免反复地尝试访问不存在的资源。
    The absence of a particular module or artifact in a particular repository, eliminating repeated attempts to access a resource that does not exist.

每个元数据缓存中的条目包括了一条存储库中提供的信息,以及可用于缓存到期的时间戳的记录。
Every entry in the metadata cache includes a record of the repository that provided the information as well as a timestamp that can be used for cache expiry.

50.9.1.2. 仓库缓存是独立的

50.9.1.2. Repository caches are independent

如上文所述,每个仓库是一个单独的元数据缓存。一个仓库由它的 URL、类型和布局来区分。如果一个模块或构件以之前没有从这个存储库中解析过,Gradle 将尝试在这个存储库中解析这个模块。这将始终涉及到存储库中的远程查找,然而,在许多情况下都没有下载的需要(见第 50.9.1.3 节,“构件重用”下文)、。
As described above, for each repository there is a separate metadata cache. A repository is identified by its URL, type and layout. If a module or artifact has not been previously resolved from this repository, Gradle will attempt to resolve the module against the repository. This will always involve a remote lookup on the repository, however in many cases no download will be required (seeSection 50.9.1.3, “Artifact reuse”, below).

如果所需的构件,在构建所指定的任何仓库中都没有找到的话,依赖解析将会失败,无论本地缓存是否从一个其他的仓库中取回这个构件。仓库独立允许构建之间用一种先进方法的方法彼此隔离,以前没有构建工具能做到这样。这是一个关键的功能,能在任何环境中创建可靠,重复性好的构建。
Dependency resolution will fail if the required artifacts are not available in any repository specified by the build, regardless whether the local cache has retrieved this artifact from a different repository. Repository independence allows builds to be isolated from each other in an advanced way that no build tool has done before. This is a key feature to create builds that are reliable and reproducible in any environment.

50.9.1.3. 构件重用

50.9.1.3. Artifact reuse

在下载构件前,Gradle 试图通过下载与该项目关联的sha文件以确定所需的构件的校验和。如果校验和可以获取到,并且如果已经存在具有相同 id 和校验和的构件,则不会再去下载这个构件。如果校验和不能从远程服务器检索,构件将被下载(并且忽略它所匹配的现有的构件)。
Before downloading an artifact, Gradle tries to determine the checksum of the required artifact by downloading the sha file associated with that artifact. If the checksum can be retrieved, an artifact is not downloaded if an artifact already exists with the same id and checksum. If the checksum cannot be retrieved from the remote server, the artifact will be downloaded (and ignored if it matches an existing artifact).

同时考虑构件从不同的仓库下载,Gradle 还将试图重用本地 Maven 库中发现的构件。如果一个候选的构件已经通过 Maven 下载,并且如果它可以和远程服务器定义的校验和匹配,Gradle 将使用这个构件。
As well as considering artifacts downloaded from a different repository, Gradle will also attempt to reuse artifacts found in the local Maven Repository. If a candidate artifact has been downloaded by Maven, Gradle will use this artifact if it can be verified to match the checksum declared by the remote server.

50.9.1.4. 基于校验和的存储

50.9.1.4. Checksum based storage

不同的仓库提供不同的二进制构件以响应相同的构件标识符是可能的。这种常见的情况是 Maven 的快照构件,但任何构件也都可以不改变它的标识符而重新发布。通过基于其 SHA1 校验和缓存构件,Gradle 是能够保持同一构件的多个版本。这意味着,当对一个存储库解析时,Gradle 将永远不会覆盖从一个不同的仓库中缓存的构件文件。这不需要让一个单独的文件在每一个仓库中存储就可以做到。
It is possible for different repositories to provide a different binary artifact in response to the same artifact identifier. This is often the case with Maven SNAPSHOT artifacts, but can also be true for any artifact which is republished without changing it's identifier. By caching artifacts based on their SHA1 checksum, Gradle is able to maintain multiple versions of the same artifact. This means that when resolving against one repository Gradle will never overwrite the cached artifact file from a different repository. This is done without requiring a separate artifact file store per repository.

50.9.1.5. 缓存锁

50.9.1.5. Cache Locking

Gradle 依赖缓存使用基于文件的锁来确保,它可以安全地通过多个 Gradle 进程并行使用。每当二进制元数据存储区正在读取或写入时,锁都会被持有,但会在慢的操作比如下载远程工作时释放。
The Gradle dependency cache uses file-based locking to ensure that it can safely be used by multiple Gradle processes concurrently. The lock is held whenever the binary meta-data store is being read or written, but is released for slow operations such as downloading remote artifacts.

50.9.2. 重写缓存的命令行选项

50.9.2. Command line options to override caching

50.9.2.1. 离线

50.9.2.1. Offline

--offline 命令行开机告诉 Gradle 总是从缓存中使用依赖模块,无论它们是否被再次检查。在使用离线运行时,Gradle 将不会尝试访问网络来执行依赖解析。如果所需的模块在依赖缓存中不存在,构建执行将会失败。
The --offline command line switch tells Gradle to always use dependency modules from the cache, regardless if they are due to be checked again. When running with offline, Gradle will never attempt to access the network to perform dependency resolution. If required modules are not present in the dependency cache, build execution will fail.

50.9.2.2. 刷新

50.9.2.2. Refresh

有时,Gradle 依赖缓存可能与已配置的仓库的实际状态不同步。也许一个存储库的最初配置不正确,或许是一个“无改变”的模块被不正确地发布。要刷新依赖缓存中的所有依赖项,请使用--refresh-dependencies命令行选项。
At times, the Gradle Dependency Cache can be out of sync with the actual state of the configured repositories. Perhaps a repository was initially misconfigured, or perhaps a "non-changing" module was published incorrectly. To refresh all dependencies in the dependency cache, use the --refresh-dependencies option on the command line.

--refresh-dependencies 选项告诉 Gradle 在解析模块和构件时忽略所有缓存条目。对所有已配置的仓库执行新的解析,通过重新计算动态版本,模块刷新,以及下载构件。然而,在再次下载之前Gradle 可能将会检查前一个下载的构件是否有效。这是通过比较发布在仓库中的 SHA1 值和现在已经下载好的工件的 SHA1 值来完成的。
The --refresh-dependencies option tells Gradle to ignore all cached entries for resolved modules and artifacts. A fresh resolve will be performed against all configured repositories, with dynamic versions recalculated, modules refreshed, and artifacts downloaded. However, where possible Gradle will check if the previously downloaded artifacts are valid before downloading again. This is done by comparing published SHA1 values in the repository with the SHA1 values for existing downloaded artifacts.

50.9.3. 依赖缓存的微调控制

50.9.3. Fine-tuned control over dependency caching

你可以在一个配置中通过使用ResolutionStrategy对缓存的某些方面进行微调。
You can fine-tune certain aspects of caching using the ResolutionStrategy for a configuration.

默认情况下,Gradle 缓存动态版本的时间为 24 小时。如果要改变Gradle对解析一个动态版本的缓存时间,可以使用:
By default, Gradle caches dynamic versions for 24 hours. To change how long Gradle will cache the resolved version for a dynamic version, use:

示例 50.47. 动态版本缓存控制 - Example 50.47. Dynamic version cache control

build.gradle

configurations.all {
    resolutionStrategy.cacheDynamicVersionsFor 10, 'minutes'
}

默认情况下,Gradle 的变化模块将缓存 24 小时。要修改 Gradle 对变化模块的元数据和构件的缓存时间,请使用:
By default, Gradle caches changing modules for 24 hours. To change how long Gradle will cache the meta-data and artifacts for a changing module, use:

示例 50.48. 变化模块的缓存控制 - Example 50.48. Changing module cache control

build.gradle

configurations.all {
    resolutionStrategy.cacheChangingModulesFor 4, 'hours'
}

更多详细信息请参阅ResolutionStrategy的 API 文档。
For more details, take a look at the API documentation forResolutionStrategy.

50.10. 传递依赖管理的策略

50.10. Strategies for transitive dependency management

许多项目依赖于Maven 中央仓库。这不是没有问题的。
Many projects rely on the Maven Central repository. This is not without problems.

  • Maven 中央存储库可能会下线,或者响应时间很长。


    The Maven Central repository can be down or has a very long response time.

  • 许多项目的 POM 文件会有错误的信息(比如,commons-httpclient-3.0的POM文件声明了 JUnit 是运行时依赖)。


    The POM files of many projects have wrong information (as one example, the POM of commons-httpclient-3.0 declares JUnit as a runtime dependency).

  • 对于许多项目而言,可能不是只有正确的一组依赖(因POM格式的影响会多或少)。


    For many projects there is not one right set of dependencies (as more or less imposed by the POM format).

如果您的项目依赖于 Maven 中央仓,你很可能需要额外的自定义仓库,因为:
If your project relies on the Maven Central repository you are likely to need an additional custom repository, because:

  • 你可能需要还没有上传到Maven 中央仓的依赖。


    You might need dependencies that are not uploaded to Maven Central yet.

  • 你想要正确地处理 Maven 中央仓 POM 文件中错误的元数据。


    You want to deal properly with wrong metadata in a Maven Central POM file.

  • 你不想曝光给想要对你的项目进行构建的人,Maven 中央仓停机或者有时候响应时间太长。


    You don't want to expose people who want to build your project, to the downtimes or sometimes very long response times of Maven Central.

想在设置一个自定义的仓库并不算什么。[17]但想让这个仓库保持最新的状态,可能会很乏味。对一个新的版本,你总是要创建新的 XML 描述符和目录。你的自定义存仓库是另一个基础结构元素,它可能有停机时间并且需要更新。要启用历史版本,你需要保留所有过去的库,并且需要备份。它是一个间接层。你还要查找另外一个信息源。尽管这一切真的不是大问题,但累加起来就有影响了。仓库管理器,比如像 Artifactory 或 Nexus 则会使这些工作变得轻松。但是比如开源项目通常没有主机用于这些产品。这种状况通过一些新的服务也改变了,比如Bintray ,它可以让开发者使用自助服务的仓库平台托管和分发他们发布的二进制文件。Bintray 还支持共享经过他们审核的构件,通过JCenter公共仓库,为所有普通的OSS java 构件提供一个单一的解析地址(见第 50.6.2 节,“Maven JCenter 存储库”)。
It is not a big deal to set-up a custom repository. [17] But it can be tedious, to keep it up to date. For a new version, you have always to create the new XML descriptor and the directories. And your custom repository is another infrastructure element which might have downtimes and needs to be updated. To enable historical builds, you need to keep all the past libraries and you need a backup. It is another layer of indirection. Another source of information you have to lookup. All this is not really a big deal but in its sum it has an impact. Repository Manager like Artifactory or Nexus make this easier. But for example open source projects don't usually have a host for those products. This is changing with new services like Bintray that let developers host and distribute their release binaries using a self-service repository platform. Bintray also supports sharing approved artifacts though the JCenter public repository to provide a single resolution address for all popular OSS java artifacts (see Section 50.6.2, “Maven JCenter repository”).

这也是为什么一些项目更愿意把他们的库存储于他们的版本控件系统的原因。这种做法 Gradle 也完全支持。库可以存在一个平面目录中,而没有任何 XML 模块描述符文件。然而 Gradle 能提供完整的传递依赖管理。您可以使用客户端模块依赖,或者是工件依赖来表达依赖关系,后者的情况中第一级依赖是没有传递依赖的。人们可以从 svn 检出这样一个项目,并且具体必要的一切,来构建它。
This is a reason why some projects prefer to store their libraries in their version control system. This approach is fully supported by Gradle. The libraries can be stored in a flat directory without any XML module descriptor files. Yet Gradle offers complete transitive dependency management. You can use either client module dependencies to express the dependency relations, or artifact dependencies in case a first level dependency has no transitive dependencies. People can check out such a project from svn and have everything necessary to build it.

如果您是使用像 Git 一样的分布式版本控制系统,由于人们会检出整个历史,你可能不想使用版本控制系统来保存这些库。但即使是这样, Gradle 的灵活性也可以使你的生活更轻松。例如你可以使用一个共享平面目录,而不包括如上所述可以有完全的传递依赖管理的XML 描述符。
If you are working with a distributed version control system like Git you probably don't want to use the version control system to store libraries as people check out the whole history. But even here the flexibility of Gradle can make your life easier. For example you can use a shared flat directory without XML descriptors and yet you can have full transitive dependency management as described above.

你也可以使用混合策略。如果你主要关心的是 POM 文件和维护的自定义 XML 描述符中的元数据不正确,客户端模块提供了一种替代方案。但你当然也可以仍然使用 Maven2 仓库和你自定义的存储库,作为只放 jars和依然使用传递依赖管理的仓库。或者,你可以只为元数字不正确的 POMs 提供客户端模块。对于这些jar 和不正确的 POMs,你依然要使用远程仓库。
You could also have a mixed strategy. If your main concern is bad metadata in the POM file and maintaining custom XML descriptors, Client Modules offer an alternative. But you can of course still use Maven2 repo and your custom repository as a repository for jars only and still enjoy transitive dependency management. Or you can only provide client modules for POMs with bad metadata. For the jars and the correct POMs you still use the remote repository.

50.10.1. 隐式传递依赖

50.10.1. Implicit transitive dependencies

还有另外一种方法,用于处理没有XML 描述符文件的传递依赖。你可以使用 Gradle 来做,但我们不推荐它。我们提到它是为了完整性,以及和其他构建工具进行比较。
There is another way to deal with transitive dependencies without XML descriptor files. You can do this with Gradle, but we don't recommend it. We mention it for the sake of completeness and comparison with other build tools.

诀窍是只使用构件依赖,并在列表中对它们进行分组。对于这种方法,你将用某种方式表达,你第一级的依赖项和传递依赖是什么(见第 50.4.8 条,“可选属性”)。但缺点是,对于 Gradle 依赖管理而言,所有的依赖都被认为是第一级依赖。依赖报告不会显示你真正的依赖关系图,并且compile任务会使用所有的依赖,而不只是第一级依赖。总之,比起使用客户端模块,你的构建不再那么容易维护和可靠。而你不会有其他收获。
The trick is to use only artifact dependencies and group them in lists. That way you have somehow expressed, what are your first level dependencies and what are transitive dependencies (see Section 50.4.8, “Optional attributes”). But the draw-back is, that for the Gradle dependency management all dependencies are considered first level dependencies. The dependency reports don't show your real dependency graph and the compile task uses all dependencies, not just the first level dependencies. All in all, your build is less maintainable and reliable than it could be when using client modules. And you don't gain anything.



[14] Gradle 支持部分多项目构建(参见 第 56 章, 多项目构建)。
[14] Gradle supports partial multiproject builds (see Chapter 56, Multi-project Builds).

[16] http://ant.apache.org/ivy/history/latest-milestone/concept.html,你可以了解到更多关于 ivy 模式的内容。
[16] At http://ant.apache.org/ivy/history/latest-milestone/concept.html you can learn more about ivy patterns.

[17] 如果你想要从 Maven 中央仓库停机保护你的项目不变得更加复杂时,你可能需要设置一个仓库代理。在企业环境中,这是相当普遍的。而对于一个开放源码项目而言,看起来则有点小题大做了。
[17] If you want to shield your project from the downtimes of Maven Central things get more complicated. You probably want to set-up a repository proxy for this. In an enterprise environment this is rather common. For an open source project it looks like overkill.