Skip to content

3. 本文所用工具

本文中的示例已使用以下工具进行测试:

  • NetBeans 6.8 至 7.1.2 版本。NetBeans 的安装说明详见 [ref3] 文档第 1.3.1 节。
  • Wampserver 2.2 版。WampServer 的安装说明详见 [ref3] 文档第 1.3.3 节;
  • Maven 已集成到 NetBeans 中。下面我们将介绍该工具。

3.1. Maven

3.1.1. 简介

Maven 可在 URL [http://maven.apache.org/index.html ] 中获取。据其创建者所述:

Maven的主要目标是让开发人员能在最短时间内全面掌握开发项目的整体状态。为实现这一目标,Maven致力于解决以下几个关键问题:

  • 简化构建流程
  • 提供统一的构建系统
  • 提供高质量的项目信息
  • 提供最佳实践开发指南
  • 支持向新功能的透明迁移

Maven已集成到NetBeans中,我们将仅利用其其中一项功能:项目库的管理。这些库由所有jars格式的归档文件组成,这些文件必须位于项目的Classpath目录下。这类文件可能数量庞大。 例如,我们未来的项目将使用 Hibernate(对象关系映射器)ORM。该 ORM 由数十个 jar 归档文件组成。 Maven的优势在于它让我们无需了解所有这些细节。我们只需在项目中指定需要Hibernate,并提供所有有助于定位该ORM主归档文件的信息即可。 随后,Maven 也会一并下载 Hibernate 所需的所有库。这些被称为 Hibernate 的依赖项。某个 Hibernate 所需的库本身可能又依赖于其他存档文件,这些文件也会被一并下载。所有这些库都会被放置在一个名为 Maven 本地仓库的文件夹中。

Maven 项目易于共享。如果将其从一台计算机转移到另一台,且新计算机的本地仓库中不存在该项目的依赖项,系统会自动下载这些依赖项。

Maven既可以单独使用,也可以集成到NetBeans或Eclipse等集成开发环境(IDE)中。

在 NetBeans 中创建一个 Maven 项目:

  • 在 [1] 中,创建一个新项目,
  • 在 [2] 中,选择类别 [Maven] 和项目类型 [Java Application],
  • 在 [3] 中,指定新项目文件夹的父文件夹,
  • 在 [4] 中,为项目命名,
  • 在 [5] 中,生成项目。

让我们来查看项目的各个组成部分,并说明各自的作用。

  • 在 [1] 中:项目的各个分支:
    • [Source packages]:项目的 Java 类;
    • [Test packages]:项目的测试类;
    • [Dependencies]:项目所需的、由Maven管理的.jar包;
    • [Test Dependencies]:项目测试所需的、由Maven管理的.jar文件;
    • [Java Dependencies]:项目所需的、但未由 Maven 管理的 .jar 文件;
    • [Project Files]:Maven 和 NetBeans 的配置文件;
  • 在 [3] 中,分支 [Source Packages],

该分支包含项目中 Java 类的源代码。NetBeans 生成了一个默认类:


package istia.st.mvexemple;

/**
 * Hello world!
 * 
 */
public class App {
    public static void main(String[] args) {
        System.out.println("Hello World!");
    }
}
  • 在 [4] 分支中,[Test Packages] 分支包含该项目的测试类源代码,
  • [5],以及运行测试所需的 JUnit 3.8 库,

NetBeans 生成了一个默认类:


package istia.st.mvexemple;

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

/**
 * Unit test for simple App.
 */
public class AppTest extends TestCase {
    /**
     * Create the test case
     * 
     * @param testName
     *          name of the test case
     */
    public AppTest(String testName) {
        super(testName);
    }

    /**
     * @return the suite of tests being tested
     */
    public static Test suite() {
        return new TestSuite(AppTest.class);
    }

    /**
     * Rigourous Test :-)
     */
    public void testApp() {
        assertTrue(true);
    }
}

这是一个 JUnit 3.8 版本的测试。后续我们将使用 JUnit 4.x 版本的测试。

  • 在 [6] 版本中,[Dependencies] 分支目前为空,

该分支显示了项目所需且由Maven管理的所有库。此处列出的所有库均由Maven自动下载。因此,Maven项目需要互联网连接。下载的库将存储在本地。如果另一个项目需要本地已存在的库,则该库将不会被下载。 我们将看到,该库列表及其所在的仓库均在 Maven 项目的配置文件中定义。

  • 在 [7] 中,项目所需的、且未由 Maven 管理的库,
  • 在 [7] 中,即 Maven 项目的配置文件 [pom.xml]。POM 代表项目对象模型(Project Object Model)。我们将需要直接修改此文件。

生成的 [pom.xml] 文件如下:


<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>istia.st</groupId>
  <artifactId>mv-exemple</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mv-exemple</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
  • 第 5-8 行定义了将由 Maven 项目创建的 Java 对象(工件)。这些信息来自创建项目时使用的向导:

一个 Maven 对象由四个属性定义:

  • [groupId]:类似于包名的信息。 因此,Spring 框架的库具有 groupId=org.springframework,JSF 框架的库具有 groupId=javax.faces,
  • [artifactId]:Maven 对象的名称。 在 [org.springframework] 组中,包含以下 artifactId:spring-contextspring-corespring-beans、…… 在 [javax.faces] 组中,包含 artifactId 和 jsf-api,
  • [version]:Maven 构建成果的版本号。 因此,org.springframework.spring-core 构建产物具有以下版本:2.5.4、2.5.5、2.5.6、2.5.6.SECO1,……
  • [packaging]:工件的格式,通常为 war jar

我们的 Maven 项目将在 [istia.st] 组(第 5 行)中生成一个 [jar](第 8 行),其名称为 [mv-exemple](第 6 行),版本号为 [1.0-SNAPSHOT] (第7行)。这四项信息必须唯一地定义一个Maven工件。

第17至24行列出了Maven项目的依赖项,即项目所需的库列表。每个库由四项信息定义(groupId、artifactId、版本、打包方式)。 当如本例所示缺少 packaging 信息时,将使用 packaging jar 文件。此外还添加了 scope 字段,用于确定在项目生命周期的哪些阶段需要该库。默认值为 compile,表示该库在编译和运行时均需使用。 值 test 表示在项目测试阶段需要该库。此处 JUnit 3.8.1 库即属于此情况。如果该库不在本地仓库中,则会自动下载。

3.1.2. 运行项目

我们运行该项目:

在 [1] 中,Maven 项目构建完成后,将执行 [1]。NetBeans 控制台中的日志如下:

Scanning for projects...
...

------------------------------------------------------------------------
Building mv-exemple 1.0-SNAPSHOT
------------------------------------------------------------------------

[resources:resources]
[debug] execute contextualize
Using 'UTF-8' encoding to copy filtered resources.
skip non existing resourceDirectory D:\data\istia-1112\netbeans\glassfish\mv-pam\00\mv-exemple\src\main\resources

[compiler:compile]
Compiling 1 source file to D:\data\istia-1112\netbeans\glassfish\mv-pam\00\mv-exemple\target\classes

[exec:exec]
Downloading: http://repo.maven.apache.org/maven2/org/apache/commons/commons-exec/1.0.1/commons-exec-1.0.1.pom

Downloaded: http://repo.maven.apache.org/maven2/org/apache/commons/commons-exec/1.0.1/commons-exec-1.0.1.pom (8 KB,速率为 113.5 KB/秒)
Downloading: http://repo.maven.apache.org/maven2/org/apache/commons/commons-exec/1.0.1/commons-exec-1.0.1.jar

Downloaded: http://repo.maven.apache.org/maven2/org/apache/commons/commons-exec/1.0.1/commons-exec-1.0.1.jar (49 KB,速率为 763.6 KB/秒)
Hello World!
------------------------------------------------------------------------
BUILD SUCCESS
------------------------------------------------------------------------
Total time: 4.040s
Finished at: Thu Jun 21 10:10:40 CEST 2012
Final Memory: 13M/122M

结果显示在第 23 行。可以看出,即使在这个简单的情况下,Maven 也下载了某些组件(第 17 行和第 20 行)。

3.1.3. Maven 项目的文件系统

  • [1]:项目的文件系统位于 [Files] 标签页中,
  • [2]:Java源代码位于[src / main / java]文件夹中,
  • [3]:测试的 Java 源代码位于文件夹 [src / test / java] 中,
  • [4]:文件夹 [target] 由项目构建(build)生成,
  • [5]:此处,项目构建生成了一个名为 [mv-exemple-1.0-SNAPSHOT.jar] 的归档文件。

3.1.4. 本地 Maven 仓库

我们提到过,Maven会下载项目所需的依赖项并将其存储在本地。我们可以浏览这个本地仓库:

  • 在 [1] 中,选择 [Window / Other / Maven Repository Browser] 选项,
  • 在 [2] 中,会打开一个名为 [Maven Repositories] 的标签页,
  • 在 [3] 中,包含两个分支,一个用于本地仓库,另一个用于中央仓库。后者规模庞大。要查看其内容,需更新其索引 [4]。此更新过程需耗时数十分钟。
  • 在 [5] 中,本地仓库的库,
  • 在 [6] 中,可找到一个分支 [istia.st],该分支对应于我们项目的 [groupId],
  • 在 [7] 中,可访问本地仓库的属性,
  • 在 [8] 中,可查看本地仓库的路径。了解该路径很有用,因为有时(虽然很少见)Maven 不再使用项目的最新版本。 进行修改后发现变更未被采纳。此时可以手动删除本地仓库中对应 [groupId] 的分支。这将强制 Maven 根据项目的最新版本重新创建该分支。

3.1.5. 使用 Maven 搜索工件

现在让我们学习如何使用 Maven 搜索工件。我们从文件 [pom.xml] 的当前依赖项列表开始:


<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>istia.st</groupId>
  <artifactId>mv-exemple</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mv-exemple</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

第 17-23 行定义了依赖项,我们将对其进行修改,以便使用最新版本的库。

首先,我们移除当前的 [1] 依赖项。随后,[pom.xml] 文件被修改为:


<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>istia.st</groupId>
  <artifactId>mv-exemple</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mv-exemple</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies></dependencies>
</project>

第 17 行,被删除的依赖项已不再出现在 [pom.xml] 中。现在,让我们在 Maven 仓库中搜索该依赖项。

  • 在 [1] 中,向项目添加依赖项,
  • 在 [2] 中,需指定所查找工件的相关信息(groupId、artifactId、版本、打包类型(Type)及作用域)。 首先在 [groupId] [3] 中,
  • 在 [4] 处,我们输入 [espace] 以显示可能的工件列表。这里显示的是 [junit] 和 [jnit-dep]。 我们选择 [junit],
  • 在 [5] 中,采用相同方法,选择最新版本。打包类型为 jar,
  • 在 [6] 中,我们选择测试作用域,以表明该依赖项仅在测试时需要。

在 [6] 中,添加的依赖项已出现在项目中。文件 [pom.xml] 反映了这些更改:


<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>istia.st</groupId>
  <artifactId>mv-exemple</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mv-exemple</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
      <type>jar</type>
    </dependency>
  </dependencies>
</project>

请注意,文件 [pom.xml] 并未提及我们在 [6] 中看到的依赖项 [hamcrest-core-1.1]。 这是因为它是 JUnit 4.10 的依赖项,而非项目本身的依赖项。这一点通过 [Dependencies] 分支中不同的图标予以标示。该文件已被自动下载。

现在假设我们不知道所需工件的 [groupId] 版本。例如,我们想使用 Hibernate 作为 ORM(对象关系映射器),而这就是我们所知道的全部信息。 此时可以访问 [http://mvnrepository.com/] 网站:

在 [1] 页面中,可以输入关键词。输入 hibernate 并启动搜索。

  • 在 [2] 中,选择 [groupId]、org.hibernate 以及 [artifactId]、hibernate-core,
  • 在 [3] 中,选择 4.1.2-Final 版本,
  • 在 [4] 中,我们获得了要粘贴到 [pom.xml] 文件中的 Maven 代码。我们照做。

<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/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>istia.st</groupId>
  <artifactId>mv-exemple</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>mv-exemple</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
      <type>jar</type>
    </dependency>
    <dependency>
      <groupId>org.hibernate</groupId>
      <artifactId>hibernate-core</artifactId>
      <version>4.1.2.Final</version>
    </dependency>
  </dependencies>
</project>

我们保存了文件 [pom.xml]。随后,Maven 开始下载新的依赖项。项目进展如下:

  • 演变为 [5],其依赖项为 [hibernate-core-4.1.2-Final]。在发现该文件的仓库中,[artifactId] 同样由文件 [pom.xml] 描述。 该文件被读取后,Maven 发现 [artifactId] 存在依赖项,并将其一并下载。对于每个已下载的 [artifactId],Maven 都会重复这一操作。 最终,我们在 [6] 中发现了未直接请求的依赖项。这些依赖项通过与主 [artifactId] 不同的图标进行标识。

在本文档中,我们主要利用Maven的这一特性。这使我们无需了解所用库的所有依赖项,而是由Maven来管理它们。此外,通过在开发人员之间共享[pom.xml]文件,可以确保每位开发人员确实使用了相同的库。

在接下来的示例中,我们将仅提供所使用的 [pom.xml] 文件。 读者只需使用该文件,即可与文档保持一致的运行环境。此外,Maven项目可被主流Java开发环境(Eclipse、NetBeans、IntelliJ、JDeveloper)识别。 因此,读者可以使用自己喜欢的 IDE 来测试示例。