在 Flexmojos 中结合使用 Flex 和 Maven – 第 1 部分:初期步骤

阅读数:2902 2011 年 10 月 26 日

话题:语言 & 开发

目录

需求

预备知识

中继到高级 Flex 知识

需要的其他产品

用户水平

中级

需要的产品

示例文件

在构建自动化和项目管理方面,Maven 已轻车熟路。它在 Java 领域中存在许多年了,是许多优秀的企业项目的基础。它提供了依赖关系管理能力和它所提倡的约定是它在许多企业开发人员的工具包中的地位的有力保证。

幸运的是,主要归功于开源社区的努力工作,尤其是Marvin Froeder (@velobr),Flash 领域的开发人员可在他们的 Flex、AS3 和 AIR 构建版本中利用 Maven。它以 Maven 插件Flexmojos的形式使用。

这一系列的文章将介绍 Maven 的组成,以及如何使用 Flexmojos 插件管理 Flex 项目的每个方面,从构建和测试,一直到 ASDoc 支持和代码范围报告。

这是这个 3 部分系列的第一篇文章。本文将概述 Maven 和一些术语、Flexmojos,还提供了一个简单的 Flex 项目供您起步。本系列的第二篇文章将介绍项目设置和自动化、Flash Builder 集成、单元测试和多方面项目。最后一篇文章将深入介绍 Nexus、RSL、运行时模块、部署和构建版本分析。

Maven 案例

为什么开发人员需要构建工具?

在过去几十年来,软件开发中的一项最受关注的运动就是敏捷软件开发。对于不熟悉它的人而言,敏捷通过小型、可量化的增量来促进开发。为了在项目不断变化的情况下实现敏捷,通常采用持续集成来确保每个构建版本的稳定性和质量。这样,需要有一个构建产品的蓝图,以及一种在每次成功构建后自动测试应用程序的机制。

除了实现定期自动化构建,使用一个构建或控制脚本还会带来其他回报。首先,它可确保每个开发人员的职责明确。随着向源代码控制管理工具(以下简称 SCM)的每次签入生成一个构建版本,每位开发人员会负责确保构建版的成功。其次,它为实际项目组成提供了单一联系点。不会使构建参数在每个开发人员的机器或 IDE 上稍有不同,每位开发人员从相同的脚本构建,确保构建(以及项目设置)过程是 SCM 的一部分。最后也是最重要地,它确保产品的封装和部署会不断进行测试和细化,使转向生产环境的关键操作得到良好确立。

那么为什么选择 Maven?

Flex 领域的许多功能都兼容 Apache Ant——一个简单的任务运行工具,允许开发人员以要运行的各种流程和要传递的参数的形式编写一系列任务。

另一方面,Maven 通过在每个流程中进行约定假设,减轻了构建版本中的杂乱程度。无需显式表明在每个操作期间必须发生什么(比如传递给编译器的参数),Maven 插件会为您确定默认的设置,忽略不需要的配置。与 Ant 不同,它在本地存储库中管理依赖关系,动态下载它缺少的内容。Maven 使用 POM(项目对象模型)文件(更多信息将在“基础知识”一节中介绍)来管理项目,这些文件支持在模块化的应用程序之间共享和继承项目设置。

如何构建 Flex、AIR 和 AS3 项目?

要使用 Maven 构建和管理 Flex、AIR 和 AS3 项目,您需要Flexmojos 插件。像所有 Maven 插件一样,它已在执行项目期间(在根据需要引用和运行它时)已下载。它将设置转换为适用于 mxmlc、compc 的参数——分别对应于 SWF 和 SWC 编译器。不仅仅是构建,它还提供了自动化的单元测试、代码范围报告、运行时模块、RSL 支持、HTML 包装器、WAR 部署和 ASDoc 输出。

对于最新的 Flexmojos 版本、网站文档和目标清单(在编写本文时为 v4.0-RC2),请参见插件信息

注意:尽管 Flexmojos 位于 Sonatype.org 上,但它与它们没有任何其他形式的关联。Flexmojos 是一个开源计划,最初由一名开发人员倡导,很巧的是这位开发人员也为 Sonatype 工作(Marvin Froeder)

基础知识

在深入介绍 Flexmojos 之前,我将介绍一下 Maven 的基础知识。

约定高于配置

在本质上,Maven 提倡约定高于配置。简单来讲,如果您没有显式声明某项操作应该如何完成,Maven 将按照约定执行。因此,每位新开发人员都应该理解这里的约定。实际上,这真是不熟悉 Maven 的开发人员常常无谓地困扰的原因——Maven 对浏览了手册的开发人员不是很宽容。(相信我——这源于我的痛苦经历。)

分层结构

Maven 具有分层结构。在项目方面,每个项目可以有一组模块,这些模块本身也可以拥有要构建的模块,等等。模块可从父模块继承设置,可以根据需要改写它们。在依赖关系方面,Maven 将在一组远程存储库中查找和下载执行所需要的依赖关系。这些存储库中的每一个本身可以委托给其他远程存储库。

项目对象模型(POM)

一种 Maven 脚本称为 POM——项目对象模型。它是一种 XML 文档,列出可在项目上执行的各种操作。默认情况下,Maven 在当前的执行文件夹中查找 pom.xml。

以下是一个示例 POM:

<project>
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.justinjmoses.flexmojos-introduction</groupId>
    <artifactId>flexmojos-simplist</artifactId>

    <version>0.1-SNAPSHOT</version>

    <packaging>swf</packaging>

    <build>
        <sourceDirectory>src/main/flex</sourceDirectory>

        <plugins>
            <plugin>
                <groupId>org.sonatype.flexmojos</groupId>
                <artifactId>flexmojos-maven-plugin</artifactId>
                <version>4.0-RC2</version>

                <extensions>true</extensions>
            </plugin>
        </plugins>
    </build>
    
    <dependencies>

        <dependency>
            <groupId>com.adobe.flex.framework</groupId>
            <artifactId>flex-framework</artifactId>
            <version>4.5.1.21328</version>

            <type>pom</type>
        </dependency>
    </dependencies>
</project>

注意:这只是一个用于演示结构的简单 POM,不是一个完整的实现。

在上面的示例中,您可以看到一些基本特性:

  • 此脚本为项目定义了 groupId、artifactId、version 和 packaging(更多相关信息将在“工件”一节中介绍)。
  • 它演示了如何提供一个源代码位置供 Flexmojos 查找.as 和.mxml 文件。在本例中,我使用约定的 src/main/flex(更多相关信息将在下一篇文章中介绍)。
  • 它详细说明了将编译 SWF 文件(使用 mxmlc)的 Flexmojos 插件。
  • 它显示了对 Flex 4.5.1 框架本身的单一项目依赖关系。

注意:所有 POM 都继承自 Maven 超级 POM,该 POM 包含 Maven 所假设的许多约定。在执行时,Maven 将来自您的 POM 的配置合并到超级 POM 中。关于超级 POM 的更多细节,请参阅Maven 指南

工件

每个构建版本生成一个工件(通常是每个 POM 一个)。一个工件是一个操作或流程的结果。工件可分类为 groupId、artifactId、version 和 packaging (type) 。构建流程生成工件并将它们输出到目标文件夹中。

groupId 类似于一个包名称——通常为机构和产品的反向域。artifactId 是您产品的名称或标识符。version 是您产品的 SNAPSHOT 或版本编号(请参见“版本控制”一节)。packaging(type) 指定工件表示何种类型的包——对于 Flex 项目,您通常会使用 swc、swf、air、pom 或 zip 中的任一个。

例如,Flex 框架(4.5.1)本身为:

groupId: com.adobe.flex.framework
artifactId: flex-framework
version: 4.5.1.21328
packaging: pom

注意:您可能想知道为什么 flex-framework 为一个 POM,而不是一个 SWC 或 SWZ。这是因为 Flex 框架由一组依赖关系组成。有哪些依赖关系?打开 Flash Builder,创建一个新 Flex 项目,展开您紧挨项目下列出的 Flex SDK(参见图 1)。出于方便,有一个捆绑了这些依赖关系的 POM。

如果您希望看到此 POM 的内容,请通过这个远程位置访问它。

图 1. Flex 框架中的依赖关系

您可以自行决定您项目的相关 groupId、artifactId 和 version。跟往常一样,一致性是关键。

版本控制

一个重要的 Maven 约定是版本和快照之间的区别。尽管项目的状态不稳定,但每个版本都带有一个-SNAPSHOT后缀,以指定它不是一个稳定的版本。当构建时,Maven 将该版本是为一个快照构建版本,继续向您存储库中的相同位置部署后续迭代(在每次后续部署时使用时间戳后缀)。另一方面,会为每个构建版本构建和部署一个发行版。因此,您可以相信工件和其他内容的发行版本,假设它们从未更改。

一般而言,在准备生成发行版之前,您的项目将构建为快照(比如0.0.1-SNAPSHOT),您将不使用后缀构建和部署一次,然后增量修改版本并重新应用后缀(例如,部署0.0.1,然后将版本递增为0.0.2-SNAPSHOT)。

除此之外,实际的版本号可以是任意的,由您自行决定。一条经验规则是保留一个主要、次要和增量编号(比如1.3.9)——如果您在未来希望指定依赖关系范围,这将很有帮助。如果需要,您也可以应用一个限定符(比如0.5.2-alpha3)。

存储库

Maven 的每次安装会创建一个本地存储库。这个存储库通常名为.m2,位于用户的主目录中。在 Windows 7 上,它位于 /Users/[username]/.m2 中;在 OS X 和 Linux 上,它为~/.m2。

工件依照另一条 Maven 约定存档在存储库中:

/groupId/.../artifactId/version/artifactId-version.extension

从图 2 中可以看到,上面的 Flex 框架依赖关系的位置将为:

~/.m2/repository/com/adobe/flex/framework/flex-framework/4.5.1.21328/flex-framework-4.5.1.21328.pom

正如前面所述,这个 flex-frameworkPOM 是另一个工件,为您捆绑了依赖关系。因此,它与其他所有内容一起存档在您的存储库中。

图 2. 依据 Maven 约定自动存储 Flex 框架工件

运行 Maven

Maven 是一个命令行流程。尽管一些第三方工具可以将 Maven 集成到现代 IDE 中,但本文仅将关注命令行 Maven 流程。(请随时关注下一篇文章,其中将介绍 Flash Builder 集成。)

在您的命令行路径(PATH)上安装和设置了 Maven 库之后,就可以构建项目了,方法是进入项目的根文件夹(其中包含 pom.xml 文件)并运行:

mvn install

这将启动从 POM 创建一个工件、将它保存到 target 文件夹中,然后将它安装在您的本地存储库中的流程。如果在此过程中缺少任何依赖关系,Maven 将尝试下载它们并将其添加到您的本地目录中。

术语

目标、阶段和生命周期

Maven 流程包含 3 个部分:目标、阶段和生命周期。

  • 目标是一项操作。它可以是简单地将一个工件安装到本地存储库中,也可以是复杂地运行一系列自动化的单元测试。
  • 阶段是一组目标。任何阶段都可以绑定一个或多个目标。请包含清理(clean)、编译(compile)和测试(test)。
  • 生命周期是一个阶段序列。当您运行一个典型生命周期中的一个阶段时,您会运行该阶段即之前的所有阶段。两个主要的生命周期是 clean 和默认的生命周期。

每个生命周期内的实际阶段和其中的目标同时来自您的 POM 内的封装文件(比如 jar、swc 或 swf)和插件列表。

奇怪的组合:清理和安装

Maven 的最常见的执行过程是一种干净安装。它的执行命令为:

mvn clean install

这个简单的命令运行 clean 生命周期,然后运行默认的生命周期,一直到包含 install 阶段。在本质上,它执行以下步骤:

  • 首先,Maven 在当前文件夹中检查任何 pom.xml。从该文件,它确定基于封装文件(jar、swc、swf 等)和定义的任何插件确定运行哪些阶段和目标。
  • 然后它运行 clean 阶段。该阶段默认会从当前目录中的目标文件夹删除所有文件。
  • Maven 然后开始构建,运行默认的生命周期,一直到包含 install 阶段。默认情况下,这包括验证、编译和测试。但是,POM 中描述的具体的封装文件和 / 或插件将确定在实际安装之前和期间完成的实际目标和阶段。

插件

插件提供目标,并可选地将它们绑定到新的或现有的阶段。事实上,Maven 中全部是插件。默认生命周期内的所有核心功能都由核心插件提供。

例如,编译器插件定义两个目标:compile 和 testCompile。您可以通过编译器插件页面看到它们的设置。这两个目标分别绑定到两个独立的阶段:compile 和 test-compile。

当独立运行时,所有目标都带有相关插件的前缀。例如,运行一个目标涉及到以下模式:

plugin:goal

所以,单元测试的编译将通过以下命令完成:

mvn compile:testCompile

实际上,Flexmojos 本身是一个插件,它将各种阶段绑定到构建版本,无论是 SWC/SWF 封装文件内还是插件本身内的阶段。如果您希望运行默认生命周期外部的一个目标(比如 ASDoc 生成),您可以使用如下命令显式运行它:

mvn flexmojos:asdoc

如果您希望执行干净安装,然后运行 ASDoc,可以使用:

mvn clean install flexmojos:asdoc

Flexmojos 插件

前面已经提到,Flexmojos 是一个插件,它在本质上会将 SWF 和 SWC 封装文件添加到您的 POM 中,确保 Flexmojos 生命周期将在标准构建过程中采用。

图 3 显示了默认 SWF 和 SWC 生命周期中执行的插件和目标:

图 3. SWF 和 SWC 生命周期

AIR 生命周期与 SWF 相同,但包含一个在测试运行之后进行 AIR 签名的额外阶段。关于 Flexmojos 生命周期的更多信息,请查阅参考文档

依赖关系和存储库

Maven 的一种强大的能力是处理依赖关系。

依赖关系是一个工件

每个依赖关系以表示它的工件的形式列出。例如,对 FlexUnit 4.0-RC-1 的依赖关系类似于:

<dependency>
    <groupId>com.adobe.flexunit</groupId>
    <artifactId>flexunit</artifactId>
    <version>4.0-rc-1</version>

    <type>swc</type>
</dependency>

因此,POM 可以引用来自其他 POM 的工件,并且在一个构建版本内,Maven 将自动确定构建顺序。下一篇文章将深入介绍这一点。

本地存储库

依赖关系位于存储库中。Maven 的每次安装都会创建一个本地存储库,通常位于~/.m2 中。因为依赖关系位于您的 POM 中,所以 Maven 在尝试从远程存储库下载它之前,会首先检查本地存储库。

每次您安装项目,实际上您是在将生成的工件添加到本地存储库中。

存储库查找

当构建时,如果 Maven 无法找到一个依赖关系,它将在您定义的任何远程存储库中查找。要找到存储库,Maven 将在以下区域查找 repository 和 pluginRepository 定义:

  • 在执行 POM 中
  • 在父 POM 中(如果有)
  • 在构建版本中使用的任何 settings.xml 中(通过 -s 命令行选项配置)
  • 在用户级设置中(~/.m2/settings.xml)
  • 在全局级别设置中(M2_HOME/conf/settings.xml)

它然后在 Maven 中央存储库(在超级 Maven POM 中定义,所有 POM 都继承自它)中搜索。如果无法找到它,您的构建过程将中断,直到您修复了该问题。

查找 Flex 和 Flexmojos 依赖关系

那么,您的本地 Maven 安装如何知道在何处查找您的 POM 中列出的 Flex 和 Flexmojos 依赖关系?

Flexmojos 本身位于 Maven 中央存储库中,所有 POM 所继承的超级 POM 中引用了它。这意味着,您无需向您的 POM 中添加任何内容,Maven 就可以查找并下载它。如果您希望手动搜索 Maven 中央存储库,请访问search.maven.org

不幸的是,最新的 Flex SDK 和编译器依赖关系不再 Maven 中央存储库中。您需要将以下存储库信息添加到您的 POM 中、您本地存储库的用户级 settings.xml 中或您的 Maven 安装的 conf 文件夹下的全局级 settings.xml 中。这样,当 Maven 运行时,它知道在何处查找 Flex 框架和 Flex 编译器:

<repository>
    <id>flex-mojos-repository</id>
    <url>http://repository.sonatype.org/content/groups/flexgroup</url>
</repository>

<pluginRepository>
    <id>flex-mojos-repository</id>
    <url>http://repository.sonatype.org/content/groups/flexgroup</url>
</pluginRepository>

通过 Nexus 查找远程存储库

上面的位置指向一个 Nexus 存储库。Nexus 允许一种同时在内部和外部托管一组工件的情形。

请在以下 url 中查阅上述 Nexus:repository.sonatype.org。尝试在提供的搜索框中搜索各种工件——您可以看到各种类型和每种类型的版本。事实上,这常常是您发现各种依赖关系的哪些发行版可用的方式。我将在第三篇文章中更详细介绍 Nexus。

手动将依赖关系添加到本地存储库

如果您无法找到在任何地方托管的存储库怎么办?您可以使用 install:install-file 手动将工件添加到您的存储库。

例如,假设您希望将 as3-signals 依赖关系添加到您的构建版本中(as3-signals是一个第三方库,我将使用它作为一个例子)。您可以尝试将以下内容添加到 POM 中:

<dependency>
    <groupId>org.osflash</groupId>
    <artifactId>as3-signals</artifactId>
    <version>0.8</version>

    <type>swc</type>
</dependency>

但是,如果您尝试构建,您将可能看到与以下信息类似的信息:

[ERROR] Failed to execute goal on project flexmojos-dependencies: Could not resolve dependencies for project org.justinjmoses.flexmojos-introduction:flexmojos-dependencies:swf:0.0.1-SNAPSHOT: Could not find artifact org.osflash:as3-signals:swc:0.8 in flex-mojos-repository (http://repository.sonatype.org/content/groups/flexgroup) -> [Help 1]

Maven 无法找到列出的依赖关系。您可以尝试访问互联网,查看它是否托管在某个地方。如果找到,您可以将该存储库位置添加到您的 POM 或设置文件中。也可以简单地本地安装依赖关系。假设您位于与文件 as3-signals-0.8.swc 相同的文件夹,您可以运行一下命令来将工件添加到您的存储库:

mvn install:install-file 
-Dfile=as3-signals-0.8.swc 
-DgroupId=org.osflash
-DartifactId=as3-signals 
-Dversion=0.8 
-Dpackaging=swc

注意:这里我从 install 插件运行了 install-file 目标。我们使用 -D 选项传入参数。关于这些参数的详细信息,您可以查阅插件的 install-file 目标文件

示例 POM

以下是一个简单的示例 POM。我添加内部注释来解释 POM 的每个方面。以下是一个 Flex 4.5.1 示例。

开放是一种不错的标准:一些 XML 命名空间和一个 POM 版本。模型版本表示要使用的对象模型的版本,进而表示您将继承的 Maven 超级 POM。这个编号会不会经常更改,自 Maven 2 以来就已是 4.0.0:

<project xmlns="http://maven.apache.org/POM/4.0.0"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>

然后是此 POM 的工件信息(和可选的名称):

<groupId>org.justinjmoses.examples</groupId>
<artifactId>flexmojos-dependencies</artifactId>
<name>Flexmojos Dependencies Example</name>
<version>1.0.0-SNAPSHOT</version>

然后,我声明工件的类型。在本例中它为 SWF,它由 Flexmojos 提供,决定了默认的构建生命周期中的目标和阶段:

<packaging>swf</packaging>

接下来,我显式定义一个属性,很像您在 Ant 中所做的一样。我设置可重用的常量。这里我定义最新的 Flex 4.5.1 版本(准确的编号可在Flex SDK 页面上找到):

<properties>
<flex.version>4.5.1.21328</flex.version>
</properties>

现在,在构建版本内,我告诉 Maven 在何处(相对于当前的 POM)查找源文件。默认情况下,Flexmojos 将在源代码目录及其所有子文件夹中查找 *.mxml 和 *.as 文件:

<build>
<sourceDirectory>src/main/flex</sourceDirectory>

然后,我指定 Flexmojos 作为构建版本本身的版本。这里我使用了最新的 Flexmojos 版本 4.0-RC2:

<plugins>
<plugin>
<groupId>org.sonatype.flexmojos</groupId>
<artifactId>flexmojos-maven-plugin</artifactId>
<version>4.0-RC2</version>

扩展设置为 true,以确保 Flexmojos 默认生命周期通过上面定义的默认 SWF 封装文件来执行:

<extensions>true</extensions>

该配置列出构建版本内所有目标的所有选项。我也可以在命令行使用 -D 选项设置这些选项。下一篇文章将更详细地介绍配置设置:

<configuration>

对于 SWF 构建,我定义了主要 Application 文件(相对于上面定义的源文件夹)。默认情况下,Flexmojos 会在源目录中中查找一个.mxml 文件,所以这是可选的,但我还是添加了它:

<sourceFile>./Main.mxml</sourceFile>

我喜欢关闭没有构造函数编译器的警告——我不需要看到缺乏构造函数的警告:

<compilerWarnings>
<warn-no-constructor>false</warn-no-constructor>
</compilerWarnings>
 
</configuration>
</plugin>
</plugins>
</build>

现在列出我的 SWF 应用程序中的所有依赖关系,以确保它可以构建:

<dependencies>

第一个依赖关系是 Flex 框架本身。所有框架 SWC 都捆绑在 POM 中,所以我可以确保它们将位于构建版本中:

<dependency>
<groupId>com.adobe.flex.framework</groupId>
<artifactId>flex-framework</artifactId>
<version>${flex.version}</version>
<type>pom</type>
</dependency>

这个具体的项目使用 as3-signals— 一种第三方依赖关系。如果您希望自行运行此项目,必须手动执行 mvn install:install-file 来将 as3-signals 依赖关系添加到您的本地存储库中(参见上文):

<dependency>
<groupId>org.osflash</groupId>
<artifactId>as3-signals</artifactId>
<version>0.8</version>
<type>swc</type>
</dependency>
 
</dependencies>

最后,我添加构建版本需要的存储库。(您可以将这些条目放在您的~/.m2/settings.xml 文件中,以避免将它们包含在每个 POM 中):

<repositories>

首先,定义项目依赖关系的存储库:

<repository>
<id>flex-mojos-repository</id> 
<url>http://repository.sonatype.org/content/groups/flexgroup</url>

而且我只希望使用发行版,而不是快照。这些是默认值,但我还是添加了它们:

<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
 
</repository>
</repositories>

然后,我定义了插件(在本例中为 Flexmojos 和 Flex 编译器)的存储库。请注意,我为此存储库使用了与上述依赖关系相同的 URL:

<pluginRepositories>
<pluginRepository>
<id>flex-mojos-plugin-repository</id>
<url>http://repository.sonatype.org/content/groups/flexgroup</url>
</pluginRepository>
</pluginRepositories>
 
</project>

关于示例项目和它们的 POM,请查阅我在 github 上的 flexmojos-introduction 项目。这个具体的示例来自第三个项目(标为Dependencies)。

注意:在您大胆地开发 Maven 的过程中,您会构建一组最适合您的 POM。最初,您可以从其他项目上使用的 POM 开始,然后根据需要删除和添加功能和配置设置。总是删除您不需要的内容,这会使问题的检测更加容易,不会出现混乱。

延伸阅读

Maven 是一个强大的工具,它经常被误解和误用,被过度地随意转换。通过它的许多约定,Maven 简单、有效地解决了许多常见的问题。当所有一切正常运转时,生活就会变得美好。但是,当出现错误时,您将会庆幸您花时间学习了这些约定,节省了大量不知所措的时间。如果您遇到了困难,可以返回查看第一条原则。删除您的 POM 中所有不必要的内容,尝试隔离问题(听起来很像调试,是不是?)许多问题都是在开发人员在网络上找到的 POM 中剪切和粘贴内容时发生的——他们自己的脚本变成了配置设置的大杂烩。

您可以下载 Maven,从Github获取示例代码,并对各种构建版本进行修补。

这是一个 3 部分系列的第一篇文章。请随时关注下一篇文章,届时我们将深入剖析更复杂的项目,探讨 Flash Builder 集成、单元测试和自动项目设置。

以下是一些有用的资源:

本作品依据Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License授权

查看原文:Flex and Maven with Flexmojos – Part 1: First steps