. 依赖管理
Posted 貌似掉线
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了. 依赖管理相关的知识,希望对你有一定的参考价值。
本文禁止w3cschool转载!
翻译项目请关注Github上的地址:https://github.com/msdx/gradledoc 。
本文翻译所在分支:https://github.com/msdx/gradledoc/tree/2.0 。
更好的阅读体验请访问:http://gradledoc.githang.com/2.0/userguide/userguide.html 。
另外,android 手机用户可通过我写的一个程序浏览文档,带缓存功能的,目前0.6.1版本兼容 Android 4.0.3以上系统,项目地址如下:
https://github.com/msdx/gradle-doc-apk
翻译不易,本文采用 CC BY-NC-SA 4.0 许可协议,转载请务必署名及注明本文在CSDN博客上的出处:
https://coder.blog.csdn.net/article/details/96038994
关于我对Gradle的翻译,以Github上的项目及http://gradledoc.githang.com 上的文档为准。如发现翻译有误的地方,将首先在以上两个地方更新。因时间精力问题,博客中发表的译文基本不会同步修改。
第五十章. 依赖管理
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你正在使用Hibernate V3.0.5,也没有标准的方法来表示 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的版本通常在Manifest文件中,但当你要检查项目时它并不显而易见。如果有人让你看20个jar文件,你更愿意哪一种?名字像 commons-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的冲突版本应该被检测到,并且要么解决要么抛出异常。 如果不使用传递依赖管理,版本冲突没被检测到,那以在类路径中的无法预测的顺序将决定最终使用哪个版本的依赖。在有许多开发者更改依赖的大型项目上,成功的构建将会少之又少,因为依赖的顺序可能直接影响构建是否成功(或者在生产中是否出现错误)。
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. SeeResolutionStrategy
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 inDependencyHandler
. - 将任何依赖(传递依赖或非传递依赖)配置为强制。 如果冲突中的依赖是传递依赖,那么这种方法会很有用。 它还可用于强制第一级依赖的版本。请参阅
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 inResolutionStrategy
- 依赖解析规则是一个在 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
).
或者,有时你请求的模块可能会随着时间的推移而变化,即使是版本相同。这种变化模块类型的一个例子是Maven的SNAPSHOT
模块,它始终指向最新发布的工件。换句话说,一个标准的Maven快照是一个永远不会不变的模块,可以这样说,它是一个“变化模块”。
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".
动态版本 和 变化模块 之间的主要差别是,当你解析一个 动态版本时,你会得到真实的、静态的版本作为模块名称。当你解析一个 变化模块时,将使用你请求的版本来命名工件,但底层工件可能会随时间而变化。
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.
默认情况下,Grdale 对动态版本和变化模块的缓存时间是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插件会向项目添加了预定义的配置。例如,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
对象管理。你传给这个配置对象的闭包将通过它对应的 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 | 对外部模块的依赖,该外部模块的工件位于某仓库中,但模块元数据由本地构建指定。当你要覆盖模块的元数据时,可以使用这种类型的依赖。 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 为模块依赖提供了不同的标记法,有字符串表示法和映射表示法。模块依赖有 API 可以让你进一步配置,请查看 ExternalModuleDependency
了解有关该 API 的所有内容。该 API 提供了属性和配置方法。通过字符串表示法,你可以定义一个属性子集。而通过映射表示法,你可以定义所有属性。要访问完整的 API(包括映射或字符串表示法),你可以通过一个闭包将一个依赖指定给配置。
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.xml
或 ivy.xml
)。如果存在这样的模块描述符文件,它会进行解析,并下载此模块的工件(如 hibernate-3.0.5.jar
)及其依赖(如 cglib)。如果不存在这样的模块描述符文件,Gradle将查找名为 hibernate-3.0.5.jar
的文件。在 Maven 中,一个模块只能有一个工件。在 Gradle 和 Ivy 中,一个模块可以有多个工件。每个工件都可以有一组不同的依赖。
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. Depending on modules with multiple artifacts
如前所述,一个 Maven 模块只有一个工件。因此,当你的项目依赖于一个 Maven 模块时,这个模块的工件是什么会很明显。而对于 Gradle 或 Ivy 情况就不同了。Ivy 的依赖描述符( ivy.xml
)可以声明多个工件。关于这一点的更多信息请参阅关于 ivy.xml
的 Ivy 参考文档。在 Gradle 中,当你在一个 Ivy 模块上声明依赖时,实际上是在该模块的 default
配置上声明了一个依赖。所以你实际上依赖的工件集(通常是一些 jar 包),是与该模块的default
配置相关联的工件集。以下是这个问题上的一些情况:
- 模块的
default
配置包含了不需要的工件。你应该仅声明对所需工件的依赖,而不是依赖于整个配置。
Thedefault
configuration of a module contains undesired artifacts. Rather than depending on the whole configuration, a dependency on just the desired artifacts is declared. - 所需的工件属于非
default
配置。该配置被显式地命名为依赖声明的一部分。
The desired artifact belongs to a configuration other thandefault
. That configuration is explicitly named as part of the dependency declaration.
还有一些其他情况,需要微调依赖声明。有关示例及完整的依赖声明的参考,请参阅 DependencyHandler
。
50.4.1.2. Artifact only notation
如上所述,如果找不到模块描述符文件,那么默认情况下 Gradle 会下载一个与模块名称相同的 jar。但有时候,即便仓库中包含了模块描述符,你也希望只下载工件 jar 而不下载它的依赖。[14] 有时候你希望从仓库中下载没有模块描述符的 zip。 Gradle 提供了 仅工件 表示法,用于这些案例——只需要对你想要下载的扩展名前加个 '@'
符号:
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:
示例50.5. 仅工件表示法 - 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'
仅工件表示法将创建只下载具有指定扩展名的工件文件的模块依赖,而忽略现有的模块描述符。
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
Maven 依赖管理有分类器的概念, [15] Gradle 支持这一点。如果你想从 Maven 仓库中获取分类的依赖,可以这样写:
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. 使用分类器的依赖 - 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'
如上面的第一行所示,分类器可以和仅工件表示法一起用。
As can be seen in the first line above, classifiers can be used together with artifact only notation.
要遍历一个配置的依赖工件很容易:
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:2.3.3")
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 描述符来找出它的依赖,而是从构建文件中获取信息。客户端模块的依赖可以是正常模块依赖或工件依赖,或者是另一个客户端模块。还请查看 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 的依赖。
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 的依赖。当你使用 Groovy 开发自定义 Gradle 任务或插件时,这会很有用。
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'
如果你为一个特定配置定义了排除,那么解析这个配置或任何继承的配置时,所有依赖的被排除的传递依赖都会被过滤掉。如果你要从所有配置中排除传递依赖,那么可以使用一种简明的方式,使用 Groovy 的 spread-dot 运算符来表示此操作,如示例中所示。定义排除时,你可以只指定组织或只指定模块名称,或者两者都指定。另请查看 Dependency
和 Configuration
的 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 onResolutionStrategy
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.
其他有关依赖排除的示例,可以参考 ModuleDependency
或 DependencyHandler
。
Other examples of the dependency exclusions can be found in the reference for ModuleDependency
or DependencyHandler
.
50.4.8. 可选属性
50.4.8. Optional attributes
依赖的所有属性除了名称之外都是可选的。这取决于仓库类型,这些信息实际上用于查找仓库中的依赖。请参阅 第50.6节,《存储库》。 比如如果你使用 Maven 仓库,那么就需要定义组,名称及版本。如果你使用文件系统仓库,那么可能只需要名称或名称及版本。
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. 依赖的可选属 以上是关于. 依赖管理的主要内容,如果未能解决你的问题,请参考以下文章