3.9 依赖关系的管理

    开发具有一定规模的程序时,难以避免地会使用到一些库。程序所依赖的库的依赖关系的定义也应该作为版本管理的对象。

    3.9.1 依赖关系管理系统

    现在各开发语言一般都会提供以下 3 点的组合。

    • 管理通用库的仓库

    • 定义对库的依赖关系的文件

    • 使用上述文件实际管理依赖关系的脚本

    下面列举各开发语言提供的一些主要工具。

    ●…… JVM 语言

    为了管理 Java 或 Scala 等在 JVM 上运行的语言的依赖关系,有着各种各样的工具。

    • Apache Ant67 (+Apache ivy68 )

    • Maven 69

    • sbt 70

    • Gradle 71

    67 http://ant.apache.org/

    68 https://ant.apache.org/ivy/

    69 http://maven.apache.org/

    70 http://www.scala-sbt.org/

    71 http://www.gradle.org/

    这些工具都参照下面 Maven 的仓库作为共通的仓库。

    • Maven 中央仓库 72

    • Sonatype(中央仓库镜像) 73

    72 http://search.maven.org

    73 https://oss.sonatype.org

    如果制作了可以作为 OSS 公开的通用库的话,只要上传到上述仓库,就能在全世界范围内共享。

    还可以在公司内部构建 Maven 的仓库。只想在公司内部共享的库等,可以上传到公司内部的 Maven 仓库中进行管理。

    ●…… 脚本语言

    每个脚本语言都有自己各式各样的依赖关系的管理工具。

    • CPAN74 (Perl)

    • PyPl75 (Python)

    • RubyGems76 (Ruby)

    • npm77 (Node.js)

    74 http://www.cpan.org/

    75 https://pypi.python.org/pypi

    76 http://rubygems.org/

    77 https://npmjs.org/

    和 JVM 语言不同,脚本语言的仓库和工具是相同的。这是因为脚本语言较早地采用了包(package)管理的思考方式,并一直在进行整理。另一方面,JVM 语言因为长时间没有采用这种思考方式,所以各类工具显得有点混乱。

    ●…… 管理依赖关系的优点

    例如 Maven 中的依赖关系可以像下面这样定义。

    <dependencies> <dependency> <groupId>org.jyaml</groupId> <artifactId>jyaml</artifactId> <version>1.3</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> </dependency> </dependencies>

    这样定义后,Maven 会自动地从仓库中找出 jyaml 和 junit,并将其加到 ClassPath 中。如果只是处理这些的话,你可能会觉得这和在网上查找库并手动下载,然后再添加到 ClassPath 没什么区别。事实上并非如此。

    不仅是 Maven,上述列举的各个工具都还能够管理传递依赖。具体来说,如果 jyaml 和 junit 自身有依赖的库的话,就会对其进行查找,找到的库如果还依赖其他的库,则继续查找下去。也就是说,这些工具具有自动管理所有传递的依赖关系的机制。

    这样,依赖关系也能作为可以重复执行的内容被纳入到版本管理的对象之中了。如果手动操作的话,不仅容易遗漏库,再加上环境差异等原因,也非常麻烦。因此在开发现场依赖管理工具是必不可少的。

    上面以 Maven 为例进行了说明。其实 CPAN 也好,RubyGems 也好,基本的思考方式都是一样的。在接下来的开发中,让我们一起使用依赖管理系统进行有效地管理吧 78 。

    78 各个工具的详细用法在 Web 上有很多相关的信息可供参考。