Deploying

Java 的部署问题确实有点棘手。现如今有两种主流的方式:使用框架或者灵活性更高的内部研发的解决方案。

Frameworks

由于 Java 的部署并不容易,所以使用框架还是很有帮助的。最好的两个框架是 [Dropwizard][dropwizard] 和 [Spring Boot][springboot]。[Play 框架][play] 也可以被看作为一种部署框架。

这些框架都是尽力地降低你部署代码的壁垒。它们对 Java 新手或者想提高效率的人尤有帮助。单独的 JAR 包部署会比复杂的 WAR 包或者 EAR 包部署更简单一点。

然而,这些框架并没有你想象的那么灵活,如果你的项目的开发者选择的框架并不合适,你不得不迁移到手动配置更多的部署方案上来。

Maven

不错的替代工具: [Gradle][gradle].

Maven 仍然是构建,打包和测试的标准。有很多不错的替代工具,如 Gradle,但是他们同样都没有像 Maven 那样的适应性。如果你是 Maven 新手,你应该从[Maven 实例][mavenexample]这里开始。

我喜欢用一个根 POM(Project Object Model,项目对象模型)来管理所有用到的外部依赖。它会像[这个样子][rootpom]。这个根 POM 仅仅包含一个外部依赖,但是如果你的产品足够大,你将会有几十个外部依赖了。你的根 POM 应该像其他 Java 项目一样采用版本控制和发布的方式,有一个自己的项目。

如果你认为你的根 POM 每添加一个外部依赖都打上一个标签很麻烦,那你肯定没有遇到过为了排查依赖错误引起的问题,浪费一周的时间翻遍整个项目的情况。

你所有的 Maven 项目都应该包含你的根 POM,以及这些项目的所有版本信息。这样你会清除地了解到你们公司选择的每一个外部依赖的版本,以及所有正确的 Maven 插件。如果你要引入很多的外部依赖,它将会是这样子的:

  1. <dependencies>
  2. <dependency>
  3. <groupId>org.third.party</groupId>
  4. <artifactId>some-artifact</artifactId>
  5. </dependency>
  6. </dependencies>

如果你想使用内部依赖,它应该被每一个单独项目的 部分来管理。否则那将会很难保持根 POM 的版本号是正常的。

Dependency Convergence

Java 最好的一方面就是拥有大量的第三方库可以做任何事。基本上每一个 API 或者工具包都有一个 Java SDK,可以很方便的用 Maven 引入。

并且这些第三方 Java 库本身依赖特定版本的其他的库。如果你引入足够多的库,你会发现有些库的版本是冲突的,像这样:

  1. Foo library depends on Bar library v1.0
  2. Widget library depends on Bar library v0.9

你的项目到底要引入哪一个版本呢?

如果你的项目依赖于不同版本的同一个库,使用 [Maven 依赖趋同插件][depconverge]构建时将会报错。然后你有两个方案来解决这个冲突:

  1. 在你的 dependencyManagement 部分明确地支出你所使用的 Bar 的版本号
  2. 在 FOO 或者 Widget 中排除对 Bar 的依赖。

这两个方案到底选哪一个要看你面对的是什么情况:如果你想跟踪一个项目的版本,那么选择排除的方案是不错的。另一方面,如果你想明确地指出它,你可以选择一个版本,尽管你在需要更新其他依赖的时候也需要更新它。

Continuous Integration

很明显,你需要某种形式的持续集成服务器来帮你不断构建你的快照版本和基于 git 标签构建。

[Jenkins][jenkins] 和 [Travis-CI][travis] 就成了很自然的选择.

代码覆盖率非常有用,[Cobertura][cobertura] 就有 [一个很好的 Maven 插件][coberturamaven]
[a good Maven plugin][coberturamaven] 并且支持 CI。还有一些其他的支持 Java 的代码覆盖率工具,但是我只用过 Cobertura。

Maven repository

你需要一个地方存储你生成的 JAR 包,WAR 包或者 EAR 包,因此,你需要一个仓库。

一般选择有 [Artifactory][artifactory] 和 [Nexus][nexus] 这两个。它们都可以用,但是它们都有着各自的优缺点。

你应该有自己的 Artifactory/Nexus 设备和[镜像][artifactorymirror] 使你的依赖基于此。这样就不会由于上游的 Maven 库宕机而使你的构建崩溃了。

Configuration management

现在,你的代码已经编译完了,你的仓库也跑起来了,最终你需要把你的代码从开发环境部署到生产环境了。到了这里,千万不要吝啬,因为将来很长一段时间,你会从这些自动化方式中尝到很多的甜头。

[Chef][chef],[Puppet][puppet],和 [Ansible][ansible] 是很典型的选择。我曾经也写了一个叫 [Squadron][squadron] 的也可供选择,当然,我认为你应该仔细看看这个,因为它使用起来比其他的更为简单方便。

无论你选择了什么工具,不要忘了使你的部署实现自动化。