领先一步
VMware 提供培训和认证,以加速您的进步。
了解更多Apache Maven 是一款流行的开源工具,它采用“约定优于配置”的方法来管理项目构建。事实上,Eclipse 社区调查显示,Maven 的采用率从2009年的8%上升到2010年的28%,这突显了它在各种项目设置中的实用性。即使你可以在不使用 Maven 的情况下使用 Spring,但仍然有很多理由推荐 Spring 开发人员使用它。在这篇文章中,我将向您展示如何开始使用 Maven,以及如何在 Spring 库、存储库和工具(如SpringSource Tool Suite和Spring Roo)中成功地使用它。
Maven 处理项目构建。如果您的项目遵循 Maven 的约定,Maven 可以相对轻松地提供强大的功能和复杂性。它是声明式的;您描述的是想要做什么,而不是如何去做。如果您来自 Make 或 Ant 等久负盛名的构建工具,这种方法看起来会有所不同。
您在 Maven 项目配置中声明项目的依赖项。然后,这些依赖项将代表您解析并下载。这类似于许多不同操作系统中发现的包系统。假设您正在使用 OS X 的fink
或ports
命令行工具。要更新操作系统的功能,用户可以选择要安装的包(例如,最新的安全补丁或新版本的glib
库)在一个管理客户端中,然后指示客户端从称为包存储库的知名服务器下载并安装它。下载包后,包管理器会查阅包的清单,其中列出了包所依赖的所有库(在其他包中找到)——它的传递依赖项。这些也会被下载。
有几种方法可以安装 Maven,如果您还没有安装它。从Apache 网站下载它。选择较新的版本。目前,许多人使用 Maven 2.21 或最近发布的 Maven 3。下载您想要使用的版本,然后将其解压缩到您选择的目录。或者,一些操作系统在包系统中提供 Maven 2 构建(以及即将推出的 Maven 3 构建)。例如,在 Ubuntu 上,您可以运行sudo apt-get install maven2
。如果您使用的是 SpringSource Tool Suite(可在此免费下载),那么您无需担心,Maven 已经下载并包含在您的 STS 安装文件夹中。无论您如何获得系统上的 Maven 二进制文件,都要确保二进制文件在操作系统的搜索路径上。通常,这只是将 Maven 安装的bin
文件夹添加到操作系统的PATH
变量的问题。创建一个 Maven 安装本身的系统变量(称为MAVEN_HOME
)也是一个好习惯。在 Unix(包括 OS X)或 Linux 机器上,此设置看起来大致相同。在我的机器(一台 Ubuntu Linux 机器)上,它看起来像这样
export MAVEN_HOME=/home/jlong/bin/springsource/maven-2.2.1.RELEASE export PATH=$PATH:$MAVEN_HOME/bin
要测试它,打开一个新的 shell 并发出以下命令
mvn --version
您应该会看到一些输出确认命令存在于您的系统上,如下所示
jlong@jlong-mbp:~/Desktop/code$ mvn --version Apache Maven 2.2.1 (r801777; 2009-08-06 12:16:01-0700) Java version: 1.6.0_22 Java home: /usr/lib/jvm/java-6-sun-1.6.0.22/jre Default locale: en_US, platform encoding: UTF-8 OS name: "linux" version: "2.6.35-22-generic" arch: "amd64" Family: "unix" jlong@jlong-mbp:~/Desktop/code$
Maven 项目采用标准目录结构,至少看起来像这样
./pom.xml ./src ./src/main ./src/main/java ./src/main/resources ./src/test ./src/test/java ./src/test/resources
在目录结构的根目录中是一个 XML 文件(始终称为 pom.xml),Maven 期望它存在。pom.xml
(POM 是 Project Object Model 的缩写)描述了特定于您的项目且无法自动推断的事物,例如依赖项、项目名称等。
目录 | 描述 目录内容(相对于项目根目录) |
---|---|
src/main/java | 包含项目的 Java 源代码 |
src/main/resources | 包含项目的任何类路径相关的资源(例如,Spring 应用程序上下文 .xml 文件) |
src/test/java | 包含测试类的 Java 源代码。此目录将不包含在最终构建中。此处的所有测试都将被编译,所有测试都将被运行。如果测试失败,它将中止构建。 |
src/test/resources | 此目录将不包含在最终 Java 构建中。此文件夹包含测试代码的任何类路径相关的资源(例如,Spring 应用程序上下文 .xml 文件)。 |
让我们构建一个使用 Spring Framework 的简单 Maven 项目。在您的硬盘上设置一个如上的目录结构。如果您使用的是类 Unix 操作系统,您可以使用以下命令来处理在项目目录中设置目录。
mkdir spring-example1; cd spring-example1; mkdir -p src/{test,main}/{java,resources}
创建一个名为pom.xml
的文本文件。在文件中输入以下内容
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springsource.greenbeans.maven</groupId>
<artifactId>example1</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Our Simple Project</name>
</project>
现在让我们忽略此文件的内容。我们只需要知道该文件的内容足以唯一地标识 Maven 项目,并让 Maven 完成其工作。让我们直接跳到结果:在项目的根文件夹中——与pom.xml
相同的文件夹中——在命令行上运行以下命令
mvn install
第一次运行可能需要(相当)一段时间。您将看到许多下载进度数字快速地在屏幕上滚动。这些进度数字表示 Maven 的依赖项和插件正在下载。Maven 没有构建“目标”的概念。相反,Maven 具有生命周期阶段的概念。这里,install
是一个阶段。这些阶段按顺序依次调用。对于每个阶段,都会注册和调用预打包的插件。Maven 已经配置了良好的默认插件,因此您通常不需要过多地处理它,但这有助于了解正在发生的事情。用户可以覆盖或添加插件并配置它们以在任何所需的阶段运行。当调用一个阶段时,所有在其之前的阶段都将首先被调用。以下是标准阶段以及每个阶段意图的解释。请记住,不同的项目可能会为这些阶段配置不同的插件。
阶段 | 描述 |
---|---|
validate | 对项目本身运行健全性检查 |
compile | 编译源代码 |
test | 运行已编译的测试类(委托给特定的单元测试插件运行程序,例如 jUnit 或 TestNG) |
package | 从已编译的代码和类路径资源生成工件,并将其存储在项目根目录下的target 文件夹中 |
integration-test | 处理并将打包的工件部署到集成测试环境 |
verify | 运行检查以确认包有效 |
install | 将打包的工件安装到本地存储库中。您的本地存储库是保存和缓存所有已下载依赖项的文件夹。随后尝试解析缓存中已存在的依赖项的构建不会重新下载依赖项,而是使用本地存储库中的依赖项。通常,它位于您的主目录下,位于.m2 中,在一个名为repository 的文件夹中。因此,在我的系统上,这将是/home/jlong/.m2/repository |
deploy | 将最终工件复制到另一个环境。通常是一个共享服务器,以便不同的团队可以共享共享依赖项。 |
因此,Maven 构建遵循阶段,每个项目最终都会通过这些阶段运行来生成工件。您可以通过在 pom.xml 文件中指定<packaging>
元素来更改生成的工件的类型。在上面的示例中,我们省略了packaging
元素,这将其留为类型为jar
的打包。其他打包类型包括war
和ear
。
考虑到所有这些,我们上面简单的调用应该看起来非常强大!
mvn install
指示 Maven——除其他事项外——下载所有插件和依赖项(如果尚未下载和缓存)、编译源代码、运行单元测试、构建 .jar、将生成的 .jar 安装到相对于项目根目录的 target 文件夹中,并将生成的 .jar 安装到本地存储库~/.m2/repository
中。由于阶段是标准的,目录是标准的,并且默认配置的插件是标准的,因此您应该能够获取任何 Maven 项目,并运行mvn install
并可预测地获得经过测试的可用二进制文件。
有时您希望 Maven 删除“target”文件夹中的所有内容并重新开始。为此,您可以在“install”命令之前使用“clean”命令。这将删除任何预构建的二进制文件,然后安装工件。
mvn clean install
所有 Maven 项目都可以通过其artifactId
、groupId
和version
元素的组合唯一标识。此信息提供项目的“坐标”。我们在pom.xml
文件中指定的信息告诉 Maven 我们项目的坐标是什么。Maven 可以通过指定具有唯一坐标的依赖项,在编译和执行期间自动将其他工件(依赖项)添加到项目的类路径。以下是坐标三个最重要部分的概述。
坐标元素 | 描述 |
---|---|
groupId | groupId 可以是任何东西。将其视为项目的 Java 包。通常,它是您组织的域名以及项目的组合。例如,Spring Integration 项目的groupId 为:org.springframework.integration |
artifactId | artifactId 是groupId 中此特定工件的名称。groupId 可能对许多不同的工件是通用的,这些工件共同描述了一个完整的系统。ArtifactIds 可以按用途、模块名称或任何其他鉴别符命名。Spring Integration 文件支持具有以下artifactId :spring-integration-file |
Version | 这是项目的版本。Maven 版本可以是固定数字或快照。项目的最终 GA 版本可能具有 1.0 或 3.5 等版本。但是,在开发中,这些相同的项目将被称为最终版本的快照。Maven 可以使用 SNAPSHOT 后缀来适应这一点,这告诉 Maven“获取最新的构建”。例如版本可能是 1.0-SNAPSHOT,这意味着“1.0 的最新构建”。 |
我们的项目唯一标识自己
<groupId>org.springsource.greenbeans.maven</groupId>:<artifactId>example1</artifactId>:<version>1.0-SNAPSHOT</version>
安装此项目后,任何其他项目都可以通过将其作为依赖项添加到您的 Maven pom.xml 文件中来依赖它。这对于其他项目也适用。让我们修改 pom.xml 以依赖于 Spring Framework。新的 pom.xml 文件将如下所示
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springsource.greenbeans.maven</groupId>
<artifactId>example2</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Our Simple Project</name>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
</dependencies>
</project>
重新运行mvn install
,你应该会看到Spring Framework库及其依赖库开始下载。检查输出,你会看到Maven正在从公共仓库http://repo1.maven.org
下载依赖项。有很多公共仓库,Maven默认会查询其中几个。这些仓库只是带有目录的HTTP服务器。你通常可以在浏览器中检查它们,以搜索你想要的特定依赖项。例如,如果我想查看所有可用的Spring Framework依赖项,可以浏览URLhttp://repo1.maven.org/maven2/org/springframework/
。要查看所有Spring Integration依赖项,请浏览http://repo1.maven.org/maven2/org/springframework/integration/
。要查看所有Spring Batch依赖项,请浏览http://repo1.maven.org/maven2/org/springframework/batch/
,等等。SpringSource还维护着几个Maven仓库,其中包含我们最新的依赖项,例如http://maven.springframework.org
和spring-roo-repository.springsource.org
这些仓库都遵循通用的布局,并且都包含关于存储在标准位置的每个构件的元数据。这种仓库结构已经成为事实上的标准,现在其他工具也经常使用它们。除了Maven之外,还有其他更专业的构建工具现在也使用并生成与Maven相同的元数据。
Maven的默认设置对于大多数构建来说已经足够了,但在某些情况下,你可能需要调整Maven在构建阶段的行为,或者在某些情况下添加可以在任何阶段之外调用的功能。在Maven中,你使用插件来更改这些内容。我经常更改的一件事是编译器的语言支持。我通常希望使用Java 5或更高版本,而Maven 2的默认行为是1.4。我们将覆盖默认的Maven编译器行为并配置特定的语言兼容性。下面是更新后的Maven项目文件。
<?xml version="1.0" encoding="UTF-8"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springsource.greenbeans.maven</groupId>
<artifactId>example2</artifactId>
<version>1.0-SNAPSHOT</version>
<name>Our Simple Project</name>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.0.5.RELEASE</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.3.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
有很多可用的插件,还有许多其他插件是由各种社区项目贡献的。插件的一个常见用例是将aspectj-compiler
插件添加到编译阶段,以确保AspectJ方面被正确编译。另一个常见需求是为基于WSDL的Web服务契约生成Java接口。通常,插件本身很有用,并且不与任何特定的构建阶段绑定。Maven允许你调用单个插件,而无需调用整个构建。插件通常提供几个特定的命令。要调用插件,可以使用以下形式
mvn [plugin-name]:[command-name]
插件名称可以是别名,也可以是完全限定的插件名称。来自Maven项目仓库的插件是别名,易于使用。一个非常有用的插件是Maven依赖项插件。依赖项插件支持许多命令。人们的一个常见需求是获取附加到给定项目的所有依赖项(传递性或其他)的清单。Maven依赖项插件可以打印一个树,显示项目的全部依赖项。像这样调用它
mvn dependency:tree
注意:此插件的输出在Maven 3中不可靠,并且STS也包含一个相互关联依赖项的可视化图表。在我的系统上,输出如下所示
jlong@jlong-mbp:~/Desktop/mavenspring/code/example1$ mvn dependency:tree [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'dependency'. [INFO] ------------------------------------------------------------------------ [INFO] Building Our Simple Project [INFO] task-segment: [dependency:tree] [INFO] ------------------------------------------------------------------------ [INFO] [dependency:tree {execution: default-cli}] [INFO] org.springsource.greenbeans.maven:example1:jar:1.0-SNAPSHOT [INFO] +- log4j:log4j:jar:1.2.16:compile [INFO] +- org.springframework:spring-jdbc:jar:3.0.5.RELEASE:compile [INFO] | +- org.springframework:spring-beans:jar:3.0.5.RELEASE:compile [INFO] | +- org.springframework:spring-core:jar:3.0.5.RELEASE:compile [INFO] | | \- commons-logging:commons-logging:jar:1.1.1:compile [INFO] | \- org.springframework:spring-tx:jar:3.0.5.RELEASE:compile [INFO] | \- aopalliance:aopalliance:jar:1.0:compile [INFO] +- org.springframework:spring-context:jar:3.0.5.RELEASE:compile [INFO] | +- org.springframework:spring-aop:jar:3.0.5.RELEASE:compile [INFO] | +- org.springframework:spring-expression:jar:3.0.5.RELEASE:compile [INFO] | \- org.springframework:spring-asm:jar:3.0.5.RELEASE:compile [INFO] \- junit:junit:jar:4.5:compile [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 4 seconds [INFO] Finished at: Wed Jan 10 02:07:36 PST 2011 [INFO] Final Memory: 22M/279M [INFO] ------------------------------------------------------------------------ jlong@jlong-mbp:~/Desktop/mavenspring/code/example1$
现在你知道依赖关系图是什么样子了。另一个常见问题是如何在一个文件夹中汇集所有依赖项。这对于最近使用Spring Framework的用户来说尤其常见。核心Spring Framework不再附带所有提供的依赖项,因为像Maven这样的工具使获取所有依赖项更容易。特别是dependency
插件使这更容易。运行mvn dependency:copy-dependencies
命令,所有依赖项将被放入项目的target/dependency/
文件夹中。这是在我的系统上的输出
jlong@jlong-mbp:~/Desktop/mavenspring/code/example1$ mvn dependency:copy-dependencies [INFO] Scanning for projects... [INFO] Searching repository for plugin with prefix: 'dependency'. [INFO] ------------------------------------------------------------------------ [INFO] Building Our Simple Project [INFO] task-segment: [dependency:copy-dependencies] [INFO] ------------------------------------------------------------------------ [INFO] [dependency:copy-dependencies {execution: default-cli}] [INFO] Copying aopalliance-1.0.jar to /home/jlong/...example1/target/dependency/aopalliance-1.0.jar [INFO] Copying commons-logging-1.1.1.jar to /home/jlong/...example1/target/dependency/commons-logging-1.1.1.jar [INFO] Copying junit-4.5.jar to /home/jlong/...example1/target/dependency/junit-4.5.jar [INFO] Copying log4j-1.2.16.jar to /home/jlong/...example1/target/dependency/log4j-1.2.16.jar [INFO] Copying spring-aop-3.0.5.RELEASE.jar to /home/jlong/...example1/target/dependency/spring-aop-3.0.5.RELEASE.jar [INFO] Copying spring-asm-3.0.5.RELEASE.jar to /home/jlong/...example1/target/dependency/spring-asm-3.0.5.RELEASE.jar [INFO] Copying spring-beans-3.0.5.RELEASE.jar to /home/jlong/...example1/target/dependency/spring-beans-3.0.5.RELEASE.jar [INFO] Copying spring-context-3.0.5.RELEASE.jar to /home/jlong/...example1/target/dependency/spring-context-3.0.5.RELEASE.jar [INFO] Copying spring-core-3.0.5.RELEASE.jar to /home/jlong/...example1/target/dependency/spring-core-3.0.5.RELEASE.jar [INFO] Copying spring-expression-3.0.5.RELEASE.jar to /home/jlong/...example1/target/dependency/spring-expression-3.0.5.RELEASE.jar [INFO] Copying spring-jdbc-3.0.5.RELEASE.jar to /home/jlong/...example1/target/dependency/spring-jdbc-3.0.5.RELEASE.jar [INFO] Copying spring-tx-3.0.5.RELEASE.jar to /home/jlong/...example1/target/dependency/spring-tx-3.0.5.RELEASE.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESSFUL [INFO] ------------------------------------------------------------------------ [INFO] Total time: 3 seconds [INFO] Finished at: Wed Jan 12 02:18:02 PST 2011 [INFO] Final Memory: 22M/279M [INFO] ------------------------------------------------------------------------ jlong@jlong-mbp:~/Desktop/mavenspring/code/example1$
Maven鼓励可重复构建。命令是标准的,阶段、插件配置和项目类型都是标准的。任何安装了Maven的开发人员都应该能够获取项目的源代码及其pom.xml文件,并将其完全按照原始开发人员在其私人工作站上构建的方式进行重建。理论上,不需要在构建文件中四处搜索以调试构建逻辑,几乎不需要做任何技巧来设置构建所需的运行环境(属性文件、shell变量等)。这
Maven的pom.xml
文件指定了构建项目所需的一切。它指定了编译需要哪些库,知道使用哪个编译器,知道源代码放在哪里。它知道你项目的所有信息。因此,像SpringSource Tool Suite这样的优秀工具包含导入Maven项目的功能(即M2Eclipse
插件,它为Eclipse衍生产品提供了出色的Maven支持)就不足为奇了。首先,我们需要将项目导入STS。为此:转到文件>导入>Maven>常规,然后浏览到包含你的pom.xml
的文件夹
在这个例子中,我们已经将Maven项目导入到STS环境中,但是你也可以在STS中创建基于Maven的项目。STS附带了许多使用Maven的模板项目,你可以访问它们。只需转到文件>新建>Spring模板项目
并选择其中一个项目。它们也是基于Maven的,因此它们是快速入门的好方法。
你现在在STS中拥有一个可工作的Maven项目,你可以立即开始编码。浏览“包资源管理器”。你会在你的项目中看到一个“Maven依赖项”库,其中包含Maven pom中指定的依赖项以及传递依赖项。你还会注意到,M2Eclipse插件已在STS中正确添加了Maven所需的四个源代码根目录。
此时,我们有一个可工作的STS项目,它已经设置了类路径并且可以正确构建。我不知道你怎么样,但我此刻的第一感觉——这个项目感觉就像一块干净的白色画布,正等待着被绘制——是想开始编写代码。毕竟,我还有工作要做!通常,我会添加jUnit并保存pom.xml文件。
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.5</version>
</dependency>
此时,STS会自动更新项目中的Maven依赖项。
然后,我通常会添加一个日志框架并保存它
```xml然后,我将开始添加我针对我的任务所需的依赖项。假设我阅读了上周关于Green Beans的文章,并想利用JDBC和Spring的JdbcTemplate
,我添加了它
我们开始了!让我们编写一些代码。这就是我最喜欢的M2Eclipse
Maven集成的功能之一发挥作用的地方。你看,亲爱的读者,我在代码中犯了很多错误。:-) 我花了很多时间运行和调试代码。我通常会破坏某些东西,需要调试我的代码和框架之间的相互作用。Maven依赖项通常与附带的源代码一起部署,因此M2Eclipse插件可以自动为你下载源代码。要查看此功能,让我们看一下JdbcTemplate
的代码。在STS中,转到导航>打开类型
。键入JdbcTemplate
,然后单击Enter
。STS首先将打开.class
(默认行为),然后尝试在后台下载源代码。几秒钟后,你应该会看到JdbcTemplate
的正确源代码。然后,你可以检查代码并设置断点,然后可以在调试器中逐步执行这些断点。方便吧?
我们已经看到SpringSource Tool Suite是使用Java(以及Spring和Maven)代码的理想环境。使用Maven和STS很容易开始使用基于Spring的应用程序。Spring Roo甚至更容易,它已经包含在STS中,并且易于在STS中使用。我个人习惯尽可能地让“Spring Roo来做”。Spring Roo为每个Spring Roo项目设置了一个优雅的Maven构建,因此创建Spring Roo项目的动作本身就为你带来了很多好处。让我们创建一个Spring Roo项目(当然,使用STS的向导!),然后看看Spring Roo对Maven的支持如何简化Maven构建的配置。
在STS中,转到文件>新建>Spring Roo项目
。这将启动Spring Roo向导。你会注意到,向导允许你指定Maven参与的程度。保留默认值 - 完整的Maven构建
-。
这将为你留下一个新的Maven项目,类似于我们的第一个示例。你需要重复我们在前面示例中包含资源文件夹的步骤。和以前一样,你拥有STS对Maven的所有支持,但是现在你还可以使用Spring Roo shell来交互和修改Maven项目配置。首先,你可以使用Roo shell安装新创建的项目
perform command --mavenCommand install
这等效于我们之前运行的mvn install
。对于任何新创建的Spring Roo项目,你都应该运行它。Spring Roo还提供方便的可脚本化shell命令来添加和删除Maven依赖项。要添加Spring Integration框架(特别是特定于文件系统的支持),你可以发出以下命令。
dependency add --groupId org.springframework.integration --artifactId spring-integration-file --version 2.0.0.RELEASE perform package
perform package
命令会生成一个完全构建的构件,因此使用此命令构建的.war
项目(例如)将准备好立即部署到你的容器中。还有一个命令dependency remove
,可用于从Maven项目中删除依赖项。
在这篇文章中,我们探讨了 Apache Maven,这是一个构建和项目理解工具。我们研究了 Maven 的“约定优于配置”理念和声明式依赖管理如何简化项目构建。为了简化操作,我们使用了 STS,它预打包了 Apache Maven、M2Eclipse
插件和 Spring Roo。