`
minstrel
  • 浏览: 47294 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Maven起步指南

阅读更多

 

 

Maven起步指南

这份指南倾向于作为第一次开始使用Maven的人的指引手册,但也可以作为一个带有常用场景解决方案和自包含的菜谱式的手册使用。对首次使用的用户,强烈推荐你顺序步过这份材料的每一部分。对比较熟悉Maven的用户,这份指南竭力作为一种能递的上手的快速解决方案。这份指南假定你已经下载并成功安装了Maven。如果没有请参阅下载和安装指南。

Ok,现在你安装了Maven,那我们就开始吧。在深入实例之前,我们简要回顾一下Maven是怎么提升你的日常工作效率,怎么来提升你和你的其他组员的协作效率。Maven确实可以为小项目所用,但是Maven的好处是通过让组员更关注于项目的利益攸关点来让项目的管理更有效率。你可以让构建基础架构这些东西留给Maven!

目录

什么是Maven?

第一眼看来Maven可以做很多事情,但本质上,Maven试图模式化项目的构建基础以提升内涵和通过清晰的途径来应用程序最佳实践来提高生产效率. Maven本质上是项目管理和沟通工具并以此来帮助管理:

  • 构建
  • 文档
  • 报告
  • 依赖
  • 源码管理
  • 版本
  • 发行

如果你想了解更多Maven的背景知识你可以参阅Maven的哲学思想Maven的历史。 现在我们现在开始聊用户如何能从使用Maven中获益。

Maven如何惠及我的开发流程?

Maven给你带来的好处是构建过程采用标准约定和实践流程来加速你的开发周期从而在等效的时间内达到更高水平的成功率。想了解Maven如何惠及你的开发流程的更多细节,请参阅使用Maven的好处

现在你可以了解一些Maven的历史和用途,以便我们能方便的进入这是的Maven实例,进而让你能流程的使用!

如何配置Maven?

默认的Maven配置已经非常实用了,如果你网络延时比较厉害或你在HTTP代理的后面,你需要一个配置文件,参见Maven配置指南来了解更多信息。

如何搭建我的第一个Maven项目?

我们准备毫不犹豫的进入制造你的第一个Maven项目中了!为了制造我们的第一个Maven项目,我们需要利用Maven的原型机制(译者注:3.0.3的官方提供的原型居然有五、六百个之多,太坑爹了)。原型是被定义为原始模式或同类项目中的基础共同点。在Maven中,原型是一个模板,一个带有一些经用户定制信息裁剪过的Maven基础工作台。我们现在准备向你展示原型的工作机理,如果你想了解更多关于原型的信息,请参阅我们的原型介绍

通向你的第一个Maven项目继续前进!为创建一个最简的Maven项目,执行下面的命令行(译者注:windows用户可能不熟悉下面的斜杠(\)是linux或unix平台的命令行换行指示符,用户完全可以删掉这个,把所有的行都写在同一行上):

mvn archetype:generate \
  -DarchetypeGroupId=org.apache.maven.archetypes \
  -DgroupId=com.mycompany.app \
  -DartifactId=my-app

只要一执行这个命令,你就会发现一些事情。首先你将注意到一个名字为my-app的路径在你的当前目录下被创建,这就是你的新项目,这个路径下包含一个文件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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
							

pom.xml 包含这个项目的Project Object Model (POM)。POM是深入Maven的基础。 必须牢记的是Maven是以项目为中心的,项目中所有的工作都围绕着POM这个概念展开。简言之,POM包含每一条关于你的项目重要的信息,在这里完全可以一站式的获得所有关于你的项目的信息。理解POM是非常重要的,我们非常鼓励新用户参看POM介绍去理解POM(译者注:这一篇我也翻译了,请翻看我的前一篇译文)。

这是一个非常简单的POM,但是仍然展示了所有的POM的关键元素,那让我们一一介绍他们,以期你能熟悉POM的概要:

  • project 这是所有Maven pom.xml的顶层元素。
  • modelVersion 这个元素指明了我们使用的POM的版本。这个模型版本很少改变,但是为了稳定性仍然强制给出,以防Maven开发者(译者注:我理解是Maven官方出于进化的目的)认为必须修改这个版本号。
  • groupId 这个元素唯一性的。groupId是全限定你的项目的关键之一,通常表现为你的组织或团体的全限定名。例如org.apache.maven.plugins就是所有的Maven自己的插件的groupId。
  • artifactId这个元素就是指明这个项目生成的首要部件的唯一名字。项目的首要部件典型的是一个JAR文件,次要部件,例如源码包,也使用这个artifactId作为他们发行名字的一部分。一个典型的Maven工件应该是这样的格式<artifactId>-<version>.<extension> (例如: myapp-1.0.jar).
  • packaging 这个元素指明这个部件的打包类型(例如:JAR, WAR, EAR等等)。这不但表明产生的部件是JAR、WAR或者EAR,而且可以明确一个构建过程的生命周期(生命周期主题我们会在这个指南的接下来部分讨论,现在,我们只要认为它指明了项目的打包方式,也扮演了部分定制构建流程的角色) 。packaging的默认值是JAR,所以大部分项目中你也不必来显式指定它。
  • version这个元素指明你的项目生产的部件的版本。Maven协助你做版本管理,你将在版本中经常见到SNAPSHOT标识符,这表明项目还在开发之中。我们将在接下来的章节中讨论snapshots是如何使用的和其工作原理。
  • name这个元素表明项目的展示名称,一般使用在配套文档中
  • url这个元素表明这个项目的访问站点,这也通常用在项目的配套文档中。
  • description这个元素给出了你的项目的基础描述,这也通常用在项目的配套文档中。

一个完整的POM元素说明手册请参阅POM手册。现在回到我们现在的这个项目。

指定原型创建出你的第一个项目以后,你也将注意到下面的目录结构被生成了:

my-app
|-- pom.xml
`-- src
    |-- main
    |   `-- java
    |       `-- com
    |           `-- mycompany
    |               `-- app
    |                   `-- App.java
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java
								

真如你所见,指定原型产生的这个项目包含了一个POM,一个源码路径树和一个测试源码路径树,这是一个标准的Maven项目结构布局(应用程序源码在${basedir}/src/main/java测试源码在${basedir}/src/test/java下,${basedir}代表包含pom.xml的路径).

如果你手工打造一个Maven项目,我们建议你也是用这样的目录结构。这是Maven的一个惯例约定,如果你要了解更对,请读一读我们的标准目录结构布局介绍

现在我们有了一个POM,一些应用程序源码,一些你可能需要的测试源码...

如何编译我的应用程序源码?

进入archetype:generate产生的pom.xml所在的目录,执行下面的命令来编译你的应用程序源码:

mvn compile

执行这条命令,你将看到下面这些:

[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO]    task-segment: [compile]
[INFO] ----------------------------------------------------------------------------
[INFO] artifact org.apache.maven.plugins:maven-resources-plugin: \
  checking for updates from central
...
[INFO] artifact org.apache.maven.plugins:maven-compiler-plugin: \
  checking for updates from central
...
[INFO] [resources:resources]
...
[INFO] [compiler:compile]
Compiling 1 source file to <dir>/my-app/target/classes
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
[INFO] Total time: 3 minutes 54 seconds
[INFO] Finished at: Fri Sep 23 15:48:34 GMT-05:00 2005
[INFO] Final Memory: 2M/6M
[INFO] ----------------------------------------------------------------------------
								

如果你第一次执行这个命令(其他情况也可能),Maven需要下载所有的需要用到的插件和相关的依赖包来服务这个命令。如果是一个干净的Maven安装,这可能需要一段时间(上面的差不多用了4分钟)。如果你再执行这个命令,Maven就有了所有的相关依赖了,就不需要再下载任何新东西了,所以执行起来也非常快。

正如你在这些回显中看到的,编译成功的类都放在了${basedir}/target/classes,这是另一个Maven使用的标准惯例。如果你仔细观察你会发现因为使用了标准惯例约定,上面的POM非常小,你不用显式的告诉Maven你的源码在哪里或者输出放到哪里。所以只要遵从Maven的标准惯例约定你将付出很小的代价就能收获颇丰!做一个简单的比较,我们在Ant完这同样的事情

现在,就只是编译一个单独的应用程序源码树Ant脚本就比我们上面的POM还多。你也许要问就这么简单的一个POM,我们能做点儿啥事儿呀!

如何编译我的源码和执行单元测试?

现在你成功编译了你的应用程序源码,现在你搞到了一些单元测试,你想编译和执行一下(因为每一个程序员都要经常协和执行单元测试*哼唧哼唧*).

执行下面的命令:

mvn test

上面的命令的回显应该如下:

[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO]    task-segment: [test]
[INFO] ----------------------------------------------------------------------------
[INFO] artifact org.apache.maven.plugins:maven-surefire-plugin: \
  checking for updates from central
...
[INFO] [resources:resources]
[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [resources:testResources]
[INFO] [compiler:testCompile]
Compiling 1 source file to C:\Test\Maven2\test\my-app\target\test-classes
...
[INFO] [surefire:test]
[INFO] Setting reports dir: C:\Test\Maven2\test\my-app\target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
[surefire] Running com.mycompany.app.AppTest
[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0 sec

Results :
[surefire] Tests run: 1, Failures: 0, Errors: 0

[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
[INFO] Total time: 15 seconds
[INFO] Finished at: Thu Oct 06 08:12:17 MDT 2005
[INFO] Final Memory: 2M/8M
[INFO] ----------------------------------------------------------------------------
								

上面的回显中有一些事情需要注意:

  • 这次Maven下载了更多的依赖,是些测试中必须的依赖包和插件(已经有了编译的依赖,所以这次编译依赖不用下载了).
  • 在编译和执行测试之前,Maven要编译我们前面主程序(这个实例中,所有的类都是最新的了,上次编译主代码之后我们没有修改主代码了)。

如果你只是想编译你的测试代码(而不像执行它),你可以执行这个命令:

 mvn test-compile

现在你可以编译你的应用程序代码,编译你的测试代码,执行你的测试了,你一定想进入下一个逻辑步骤,所以你会问...

如何创建JAR并安装到我的本地仓库中

打包一个JAR文件相当直接,可以执行一下命令:

<!-- How to skip tests ... jvz -->
mvn package

如果你看看你项目的POM,你会看到packaging元素被设置为jar。这就执行这个命令后Maven知道产生JAR文件的原因(关于这个我们后边还会说的更多)。现在你可以看一眼${basedir}/target目录,你可以看到生成的JAR文件

现在你可能想安装你生成的部件(这个JAR文件)到你的本地仓库中(你没做任何配置的话应该~/.m2/repository是你的默认本地仓库(~就是你的用户目录,windows用户可能不熟悉))。仓库的更多信息请参阅我们的仓库介绍。我们继续我们的部件安装!请执行下面的命令:

mvn install

上面的命令的回显应该如下:

[INFO] ----------------------------------------------------------------------------
[INFO] Building Maven Quick Start Archetype
[INFO]    task-segment: [install]
[INFO] ----------------------------------------------------------------------------
[INFO] [resources:resources]
[INFO] [compiler:compile]
Compiling 1 source file to <dir>/my-app/target/classes
[INFO] [resources:testResources]
[INFO] [compiler:testCompile]
Compiling 1 source file to <dir>/my-app/target/test-classes
[INFO] [surefire:test]
[INFO] Setting reports dir: <dir>/my-app/target/surefire-reports

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
[surefire] Running com.mycompany.app.AppTest
[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.001 sec

Results :
[surefire] Tests run: 1, Failures: 0, Errors: 0

[INFO] [jar:jar]
[INFO] Building jar: <dir>/my-app/target/my-app-1.0-SNAPSHOT.jar
[INFO] [install:install]
[INFO] Installing <dir>/my-app/target/my-app-1.0-SNAPSHOT.jar to \
   <local-repository>/com/mycompany/app/my-app/1.0-SNAPSHOT/my-app-1.0-SNAPSHOT.jar
[INFO] ----------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ----------------------------------------------------------------------------
[INFO] Total time: 5 seconds
[INFO] Finished at: Tue Oct 04 13:20:32 GMT-05:00 2005
[INFO] Final Memory: 3M/8M
[INFO] ----------------------------------------------------------------------------
							

注意surefire插件(用来执行测试的)寻找以约定名字命名的测试用例,默认的测试用例包括:

  • **/*Test.java
  • **/Test*.java
  • **/*TestCase.java

,默认排除在测试之外的测试用例包括:

  • **/Abstract*Test.java
  • **/Abstract*TestCase.java

你已经穿越了Maven项目中的配置、编译、测试、打包和安装这些环节。这几乎是使用Maven的项目中所有要做的事。你是否注意到你所有做的事都是拜这个只有18行内容的文件(也就是项目的模型或者POM)所赐。如果你看看典型的Ant编译文件,这个提供了同样的功能文件就已经达到了我们起步的那个POM文件的两倍之多!在我们这个POM中,在不需增加其他的配置下我们已经拥有了如此丰富的功能了,而在那个我们示例的Ant编译脚本文件中,我们哪怕要增加任何其他的一点点功能我们都需要小心翼翼的、冒着极大出错风险来增加。(译者注:作者果然是不吝溢美之词啊!不怕被Ant的人套麻袋?)

你还能免费收获什么呢?有巨量的立等可用的Maven插件,甚至就如我们上么这么简单的POM。在这我们特别指出一个Maven中颇受欢迎功能:我们的这个POM不需要任何配置工作就可以生产一个你的项目的Web站点了!你可能想定制一下你的Maven站点,但如果你没有闲工夫了,那么执行下面这个命令就能给你的项目站点提供很多基础信息了:

mvn site

有许多独立的目标动作(goals)也可以类似的执行,比如:

mvn clean

这个命令将清空target目录下所有的构建数据.

或许你想生成一个IntelliJ IDEA项目描述符?

mvn idea:idea

这个可以在开始一个新IDEA项目之前运行 - 它将设置一些配置IDEA参数,这比在IDEA中开始一个全新的项目划算多了。

如果你使用Eclipse IDE,只需要执行:

mvn eclipse:eclipse
<!-- TODO: need a sidebar notation for notes like this -->

注意:从Maven 1.0开始的一下常用的目标动作仍然可用,例如jar:jar,但是可能他们表现的不如你的预期。目前,jar:jar不会编译源文件 - 只会简单的从target/classes路径下打包JAR文件,它假定其他的工作都做好了。

如何使用插件(plug-ins)?

定制一个Maven项目的构建流程,实质就是你要增加新插件或重新配置插件。

Maven 1.0用户注意:在Maven 1.0中,你需要在maven.xml中增加一些preGoal标签以及一些project.properties标签。这里确实有一些细微的差别.

这个实例中,我们将配置JKD 5.0为编译器版本。那么就只是在你的POM增加:

...
<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>2.0.2</version>
      <configuration>
        <source>1.5</source>
        <target>1.5</target>
      </configuration>
    </plugin>
  </plugins>
</build>
...

你可以看到所有的Maven 2.0需要查找插件非常像查找依赖包 - 在某些场景他们就是一样的。这些插件会自动下载和使用,你可以指定这些插件的版本 (如果不指定,默认使用可用的最终版)。

configuration元素指定这个编译插件的每个目标动作都使用这里给定的参数。在上面的实例中,这个新的编译插件已经作为构建过程的一部分了,而仅仅是修改了一点配置。也可以给这个编译过程增加一些新目标动作。更多信息请参阅构建流程中的生命周期介绍

想要查看某个插件的可配置项请参阅插件列表,在其中找到这个插件和你使用的目标动作。想要查询如何配置某个插件的参数请看看插件配置指南

如给给我的JAR添加其他资源?

另外一个不用修改POM的常用情况是把相关资源打包进JAR文件,正如我们前面做的。为做这份常用任务,Maven仍使用标准目录布局,这意谓着使用Maven标准惯例约定你就能把资源打包进JAR包内,你仅仅是把这些资源放到标准路径下。

在下面我们的实例中,我们在路径${basedir}/src/main/resources中加入任何我们想要打包见JAR的资源就行了。Maven采用了一个简单的规则是:任何在${basedir}/src/main/resources路径下的文件夹或文件将被以同样的目录结构打包进JAR的根目录中。

my-app
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- com
    |   |       `-- mycompany
    |   |           `-- app
    |   |               `-- App.java
    |   `-- resources
    |       `-- META-INF
    |           `-- application.properties
    `-- test
        `-- java
            `-- com
                `-- mycompany
                    `-- app
                        `-- AppTest.java
            

在这个实例中我们有一个META-INF文件夹,在其中有一个application.properties文件。如果你对这个Maven创建的JAR解包,你可以可以看到如下结构:

|-- META-INF
|   |-- MANIFEST.MF
|   |-- application.properties
|   `-- maven
|       `-- com.mycompany.app
|           `-- my-app
|               |-- pom.properties
|               `-- pom.xml
`-- com
    `-- mycompany
        `-- app
            `-- App.class
						

正如你说见,${basedir}/src/main/resources下的内容被被放置在JAR的根目录下,我们的application.properties文件依然在META-INF目录下。你可能也注意到其他的一些文件像META-INF/MANIFEST.MF,还有pom.xmlpom.properties文件,这些是Maven中标准的JAR组件。你也可以选择创建你的manifest,如果不选择,Maven也会默认生成一份(你也可以修改这份文件的内容,下面我们会接触到)。pom.xmlpom.properties这两文件也被打包进JAR文件,所以每一个Maven产生的部件都是自我描述的,同时也允许你的应用程序来访问这些存储这元数据的资源文件。一个简单的实例是可以获取你的应用的版本号。访问控制POM文件需要利用一些Maven工具,但是properties文件内容可以使用标准的Java API,就像下面这样:

#Generated by Maven
#Tue Oct 04 15:43:21 GMT-05:00 2005
version=1.0-SNAPSHOT
groupId=com.mycompany.app
artifactId=my-app
						

为你的单元测试添加资源到类路径(classpath)中,你需要遵从同样的模式,就像添加资源到JAR中一样,只是这次的路径是${basedir}/src/test/resources。这次你的项目目录结构如下:

my-app
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |   `-- com
    |   |       `-- mycompany
    |   |           `-- app
    |   |               `-- App.java
    |   `-- resources
    |       `-- META-INF
    |           |-- application.properties
    `-- test
        |-- java
        |   `-- com
        |       `-- mycompany
        |           `-- app
        |               `-- AppTest.java
        `-- resources
            `-- test.properties
          	

在单元测试中你可是使用如同下面这样的简单的代码段来获取测试需要的资源:

...

// Retrieve resource
InputStream is = getClass().getResourceAsStream( "/test.properties" );

// Do something with the resource

...
						

如何过滤资源文件?(译者注:这里的过滤的意思不是扔掉,而是翻译出其引用的值,本文过滤你可以当做翻译出来读)

有时候资源文件需要包含一个仅构建时才能给定的值。Maven中,为达到这个目的,你可以把这个属性值的引用放入你的资源文件中,语法如${<property name>}。这个属性值可以是用户pom.xml中定义的,也可是用户settings.xml文件中定义的,或者是一个外部属性文件定义的属性值,甚至是系统属性

为了让Maven在复制资源文件时过滤出这些资源值,仅需在pom.xml中简单的为这个资源的路径指定filtering为true就行了:

<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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
</project>
						

你可能已经注意到我们添加了buildresourcesresource这些前面没有用过的元素标签。多说一句,我们必须显式指明我们资源所在的路径src/main/resources,所有的这些信息都是作为默认值在前面的例子使用的,只不过filtering的默认值是false,为了覆写这些默认值我们必须显式设置filtering为true。

为了引用一个在你pom.xml中定义的属性值,这个属性名就是限定你值的XML标签的名字,"pom"被定义为project (root)元素的同义词。所以${pom.name}指的是project的name的值, ${pom.version}指的是project的version值, ${pom.build.finalName}指的是这个项目打包后的最终的名字,等等。注意有一些POM元素有默认值,所以不用显式在pom.xml中定义。类似的,引用用户settings.xml中属性值可以以"settings"开始(例如,${settings.localRepository}指向用户本地仓库的路径)。

为演示这些,那我们在application.properties文件中添加一对属性值(就是我们放在src/main/resources中的) ,他们的值将在资源被过滤后被显示出:

# application.properties
application.name=${pom.name}
application.version=${pom.version}
						

只要这个资源文件位置正确,你执行下面的命令(process-resources是构建过程的生命周期的一个拷贝资源和过滤资源属性的相位(phase)):

mvn process-resources

那么target/classes下的application.properties文件(准备打包进JAR中)看上去像这样:

# application.properties
application.name=Maven Quick Start Archetype
application.version=1.0-SNAPSHOT
						

为了引用外部文件定义的属性值,你需要做的所有的工作就是把这个外部文件在你的pom.xml中显式给出。首先,我们创建一个叫src/main/filters/filter.properties的外部属性文件:

# filter.properties
my.filter.value=hello!
						

下一步,我们在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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <filters>
      <filter>src/main/filters/filter.properties</filter>
    </filters>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
</project>
						

接下来,我们在application.properties增加一个引用:

# application.properties
application.name=${pom.name}
application.version=${pom.version}
message=${my.filter.value}
					

再接下来我们执行mvn process-resources命令将把我们的新属性值过滤到application.properties中。 作为一种替代在外部文件中定义my.filter.value的属性值的做法你也可以在pom.xml中的properties段中定义,你将得到同样的效果(注意我也不必再在pom.xml中指定了到src/main/filters/filter.properties的引用了):

<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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
  <properties>
    <my.filter.value>hello</my.filter.value>
  </properties>
</project>
						

过滤资源同样也可以获得系统属性值:无论是编译进Java的系统值(如java.version或user.home)还是标准Java -D parameter 格式的命令行中定义的属性值。为演示这些, 我们把我们的application.properties文件修改为如下:

# application.properties
java.version=${java.version}
command.line.prop=${command.line.prop}
						

现在,当我们执行下面的命令(注意命令行中command.line.prop属性值的定义),这个application.properties文件将包含从操作系统获得的属性值。

mvn process-resources "-Dcommand.line.prop=hello again"

如何使用外部依赖?

可能你已经注意到了POM的dependencies我们已经在例子中使用到了。实际上,我们已经一直在使用一个外部依赖,这里我们将费一点口舌来讲讲它是如何工作。想进一步的了解,请参阅我们的依赖机制介绍

pom.xml中的dependencies段列出了所有的我们构建项目中需要外部依赖(无论是编译时,测试时,运行是或者其他等等). 现在,我们的项目只依赖JUnit(为了清晰点,我拿掉了所有的资源过滤配置):

<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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>
						

你已经注意到,每一个外部依赖至少需要定义4项内容:groupId,artifactId, version和scope。groupId, artifactId和version和pom.xml中的顶级元素project下定义的这3个元素一样。scope元素表明如何是用这个依赖,可以取值compile, testruntime。要了解关于某个依赖的所有配置信息,请参阅项目介绍手册.

<!-- DJ: Does this link work? I can't find the document. -->

要全面了解依赖的工作机理,请参阅依赖机制介绍.

Maven在构建这个项目的时候会根据这些配置信息来使用这个依赖。那Maven引用的这些依赖到底指向哪里呢?Maven会在本地仓库查(~/.m2/repository是默认的本地仓库路径)先查找一遍所有的依赖。在前面的章节中,我们我们的项目生产的部件(my-app-1.0-SNAPSHOT.jar)到本地仓库中。只要我们把部件安装到哪里,我们的另一个项目就可以把它作为依赖在他的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">
  <groupId>com.mycompany.app</groupId>
  <artifactId>my-other-app</artifactId>
  ...
  <dependencies>
    ...
    <dependency>
      <groupId>com.mycompany.app</groupId>
      <artifactId>my-app</artifactId>
      <version>1.0-SNAPSHOT</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>
						

如果依赖在其他地方呢?我如何把它放到我的本地仓库中呢?只要项目引用的依赖包在本地仓库中不存在,Maven就会从远程的某个仓库中下载它到本地仓库。你可能已经注意到,Maven在你首首次(译者注:不是每次构建新项目的首次)构建项目的时候,Maven会下载许多东西(这些下载的东西都是构建项目用到的插件)。默认的远程仓库是http://repo1.maven.org/maven2/。你也可以自己搭建一个你自己的远程仓库(可以作为你公司的中央仓库)来替代默认的远程仓库。关于仓库的更多细节,请参阅仓库介绍

我们就添加另一个依赖到我们的项目中吧。我们说我们的的代码中需要log日志,我们就添加log4j作为我们的依赖吧。首先,我们需要知道这个依赖(log4j)的groupId, artifactId和version。我们可以浏览ibiblio来查找他,或者使用"site:www.ibiblio.org maven2 log4j"在Google中查找。查找结果应该显示路径/maven2/log4j/log4j(或 /pub/packages/maven2/log4j/log4j)。(译者注,其实这些都不好用了,如果你要查找依赖包的信息可以查询http://search.maven.org/,查找插件信息可以查询http://maven.apache.org/plugins/index.html和http://mojo.codehaus.org/plugins.html),在这个路径下有一个文件maven-metadata.xml。这里log4j的maven-metadata.xml差不多是这样的:

<metadata>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.1.3</version>
  <versioning>
    <versions>
      <version>1.1.3</version>
      <version>1.2.4</version>
      <version>1.2.5</version>
      <version>1.2.6</version>
      <version>1.2.7</version>
      <version>1.2.8</version>
      <version>1.2.11</version>
      <version>1.2.9</version>
      <version>1.2.12</version>
    </versions>
  </versioning>
</metadata>
						

从这个文件中,我们可以看到我们想要的groupId是"log4j",artifactId是"log4j",很多版本可以选择;现在,我们选择最终版-1.2.12 (可能有的maven-metadata.xml显示了现在的最新版,应该比这个新). 在maven-metadata.xml旁边,我们可以找到每个版本的log4j的类库,我们可以看到实际的jar文件(e.g. log4j-1.2.12.jar),同时还有一个pom文件(这是这个依赖包的pom.xml文件,指明这个包的依赖包和一些其他信息)和另一个maven-metadata.xml文件。还有一个相应的md5文件,包含了这个文件的md5哈希值,你可以是用这个来验明你的包的正身或确认此包的的版本。

现在我们知道我我们需要的信息,我们就能添加依赖到我们的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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>log4j</groupId>
      <artifactId>log4j</artifactId>
      <version>1.2.12</version>
      <scope>compile</scope>
    </dependency>
  </dependencies>
</project>
						

现在,当我们编译这个项目(mvn compile),我们发现Maven为我们下载了log4j依赖包。

<!-- DJ: Current -->

如何部署我的JAR到远程仓库中?

为了把jar包部署到外部仓库中,你必须在pom.xml中配置仓库的url地址,同时在settings.xml配置好到这个仓库的访问授权信息。

这里是使用scp和username/password授权的配置实例(译者注:scp是ssh访问远程主机的一个命令):

<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>com.mycompany.app</groupId>
  <artifactId>my-app</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.codehaus.plexus</groupId>
      <artifactId>plexus-utils</artifactId>
      <version>1.0.4</version>
    </dependency>
  </dependencies>
  <build>
    <filters>
      <filter>src/main/filters/filters.properties</filter>
    </filters>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
  <!--
   |
   |
   |
   -->
  <distributionManagement>
    <repository>
      <id>mycompany-repository</id>
      <name>MyCompany Repository</name>
      <url>scp://repository.mycompany.com/repository/maven2</url>
    </repository>
  </distributionManagement>
</project>
            
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
                      http://maven.apache.org/xsd/settings-1.0.0.xsd">
  ...
  <servers>
    <server>
      <id>mycompany-repository</id>
      <username>jvanzyl</username>
      <!-- Default value is ~/.ssh/id_dsa -->
      <privateKey>/path/to/identity</privateKey> (默认的是~/.ssh/id_dsa)
      <passphrase>my_key_passphrase</passphrase>
    </server>
  </servers>
  ...
</settings>
						

注意:如果你连接的openssh ssh服务器已经在其sshd_confing配置中设置了"PasswordAuthentication"为"no",那么你必须么次键入你的密码来通过用户名/密码方式的授权(尽管你可以通在另外的客户端中值键入你的用户名和密码来登陆)。这种情况下你需要切换到公钥授权访问的模式(译者注:这一段我没有测试过,感觉作者正好说的好凌乱)

settings.xml中配置密码需要小心。更多信息,请参阅密码加密.

如何创建生产配套文档?

作为Maven的文档系统的替代,你可以是用Maven的原型机制为你的现有项目生成生成一个web站点,命令如下:

mvn archetype:generate \
  -DarchetypeGroupId=org.apache.maven.archetypes \
  -DarchetypeArtifactId=maven-archetype-site \
  -DgroupId=com.mycompany.app \
  -DartifactId=my-app-site
					

现在可以去站点创建指南中学习如何为你的项目创建配套文档。

如何构建其他类型的项目?

注意现有的生命周期机制适用于任何类型的项目。例如,在当前目录下,我们可以创建一个简单的web应用:

mvn archetype:generate \
    -DarchetypeGroupId=org.apache.maven.archetypes \
    -DarchetypeArtifactId=maven-archetype-webapp \
    -DgroupId=com.mycompany.app \
    -DartifactId=my-webapp
    			

注意,这些命令必须在同一行,这将新建一个文件夹my-webapp,其中包含如下的描述信息:

<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>com.mycompany.app</groupId>
  <artifactId>my-webapp</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
  <build>
    <finalName>my-webapp</finalName>
  </build>
</project>
					

注意<packaging>元素 - 这个告诉Maven来构建一个WAR包。进入这个webapp project的根目录下执行:

mvn clean package

你将看到target/my-webapp.war被构建出了,而只是执行了一些平常的步骤.

如何一次构建多个项目?

处理多模块的概念被内置进Maven 2.0。在这段,我们将向你演示怎么一步构建上面的WAR包,其中还包含了前面的JAR包。

首先,我们需要在这两个(my-app和my-webapp的父路径下增加一个父pom.xml文件,它们应该看上去像这个:

+- pom.xml
+- my-app
| +- pom.xml
| +- src
|   +- main
|     +- java
+- my-webapp
| +- pom.xml
| +- src
|   +- main
|     +- webapp
					

新建的POM应该包含如下内容:

<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>com.mycompany.app</groupId>
  <version>1.0-SNAPSHOT</version>
  <artifactId>app</artifactId>
  <packaging>pom</packaging>
  <modules>
    <module>my-app</module>
    <module>my-webapp</module>
  </modules>
</project>
					

我们要给webapp增加增加一个队我们的jar包的依赖,所以在my-webapp/pom.xml中增加如下内容:

  ...
  <dependencies>
    <dependency>
      <groupId>com.mycompany.app</groupId>
      <artifactId>my-app</artifactId>
      <version>1.0-SNAPSHOT</version>
    </dependency>
    ...
  </dependencies>
  				

最后,在子目录下的其他两个pom.xml中增加如下的<parent>元素配置:

<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">
  <parent>
    <groupId>com.mycompany.app</groupId>
    <artifactId>app</artifactId>
    <version>1.0-SNAPSHOT</version>
  </parent>
  ...
  				

现在这两个子目录的上层目录中执行:

mvn clean install

WAR包文件my-webapp/target/my-webapp.war被创建,其中我们的JAR也在其中:

$ jar tvf my-webapp/target/my-webapp-1.0-SNAPSHOT.war
   0 Fri Jun 24 10:59:56 EST 2005 META-INF/
 222 Fri Jun 24 10:59:54 EST 2005 META-INF/MANIFEST.MF
   0 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/
   0 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/com.mycompany.app/
   0 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/com.mycompany.app/my-webapp/
3239 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/com.mycompany.app/my-webapp/pom.xml
   0 Fri Jun 24 10:59:56 EST 2005 WEB-INF/
 215 Fri Jun 24 10:59:56 EST 2005 WEB-INF/web.xml
 123 Fri Jun 24 10:59:56 EST 2005 META-INF/maven/com.mycompany.app/my-webapp/pom.properties
  52 Fri Jun 24 10:59:56 EST 2005 index.jsp
   0 Fri Jun 24 10:59:56 EST 2005 WEB-INF/lib/
2713 Fri Jun 24 10:59:56 EST 2005 WEB-INF/lib/my-app-1.0-SNAPSHOT.jar
						

怎么会这样?首先父POM创建一个(app),他有pom的打包方式和一个子模块定义列表,这个告诉Maven要执行所有的子模块的构建,而不是只构建自己(如果要只构建之际可以使用--non-recursive命令行参数)。

下一步,我们告诉WAR构建过程,这里需要my-app这个JAR文件,这里做了一些事情:把JAR放到让WAR中的所有代码都可以访问到的类路径上, 让JAR一定在WAR之前构建完成, 指示WAR插件把JAR放到它的类库中。

你可能注意到junit-3.8.1.jar也是一个依赖,但是他没有进入最终的WAR,原因是<scope>test</scope>元素 - 它只需要存在在测试阶段,所以他没有进入web应用中,编译阶段的依赖也是同理。

最终的一步是执行父项目的构建,这里是不同于Maven 1.0的extend元素的作废,那个是需要POM一定被安装到仓库中,甚至他们是同一个父项目.

不同于Maven 1.0,现在不需要你执行install这个步骤了 - 你只要能在你反应堆中成功执行package命令,你就可以在你的目标路径中依赖你的其他的包了

你可能又想生产IDEA区了,那么在顶层目录下执行...

mvn idea:idea

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics