Apache Maven --- [Maven入门指南]

天大地大妈咪最大 提交于 2019-12-20 18:54:59

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

本指南的目的是为初次使用Maven的人提供一个参考,但同时也作为一个独立参考和解决方案的食谱来为常见用例提供服务.对于第一次使用的用户来说,建议按顺序依次浏览指南.而对于更加熟悉Maven的用户来说,本指南尽力提供一个急需的快速解决方案.我们假设你已经下载并成功安装了Maven,如果没有,请先查阅下载和安装说明.

好了,所以现在你已经安装了Maven,准备出发.在我们进入我们的示例之前,我们先来简单的过一遍Maven是什么,它如何帮助你的日常工作以及团队之间的协作.当然Maven可以为小项目工作,但是它的亮点是能够通过允许团队人员关注于项目利益者的需求来帮助团队更有效率的运作.你可以把构建基础委托给Maven.

什么是Maven

乍一看Maven可以是很多东西,但是简而言之,它是为了促进理解和生产,通过提供一个清晰的最优使用实践的步骤来视图将模式应用到项目的构建当中.它是一个项目综合管理工具,提供了一种方法来帮助管理:

构建

文档

报告

依赖

SCMs(供应链?)

发布

分发

Maven如何让我的开发过程受益

Maven通过采用标准规范和实践来促进你的开发周期并同时帮助你取得更高的成功.

我如何设置Maven

Maven的默认配置通常是足够使用的,但是如果你想要改变本地缓存或者绑定HTTP代理,你需要创建配置.具体查阅Maven配置指南.

我如何开始我的第一个Maven项目

我们将使用Maven的原型机制来创建我们的第一个Maven项目.一个原型被定义为一个模式或者模型,表示所有东西都以一种相同的方式被创建.在Maven中,一个原型是一个根据用户需求而定制的结合了一些用户输入来产生的Maven工作项目的模版.现在我们将向你展示一个原型机制是如何工作的,但如果你想知道更多关于原型的介绍,请参考:http://maven.apache.org/guides/introduction/introduction-to-archetypes.html

创建你的第一个项目!为了创建最简单的Maven项目,在命令行执行下列语句:

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

一旦你执行了这个命令,你将会发现一些东西发生了改变.首先,你会发现Maven为新项目创建了一个名为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>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

pom.xml包含了这个项目的项目对象模型(project object model-POM).在Maven中,POM是基础工作单元.需要牢记这一点,因为Maven天生是项目式的,一切围绕项目的概念.简而言之,POM包含了你项目的所有重要信息片并且本质上是为查找任何项目相关内容的优惠条件...理解POM的重要性,并且我们鼓励新用户查阅完整的POM介绍:http://maven.apache.org/guides/introduction/introduction-to-the-pom.html

这是一个非常简单的POM但是仍然展示了所有POM都包含的关键元素,所以让我们浏览每个元素来使你熟悉POM的要点:

<project> 在所有pom.xml文件中,它都是顶级元素

<modelVersion> 这个元素表明了这个POM正在使用的对象模型的版本.模型本身的版本很少发生变化,但是它是强制性的以确保稳定的使用如果Maven开发人员认为有必要改变模型.

<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...还表明了构建过程中的一个特定的生命周期(生命周期是一个我们将要讨论的主题,现在,只需要记住一个项目的包装可以作为定制构建生命周期的一部分).该元素的默认值是JAR,所以对于大多数项目来说你不一定要指明这个元素.

<version> 这个元素表明项目生成的工件版本号.Maven帮你进行长期的版本管理,而且你经常会看见SNAPSHOT版本标志,这表明项目正处于一个开发状态.我们将在后续讨论快照的用处和它们是如何工作的.

<name> 这个元素表明项目的展现名称.这通常被Maven用来生成文档.

<url> 这个元素表明项目站点的访问路径. 这通常被Maven用来生成文档.

<description> 这个元素提供了项目的基础描述. 这通常被Maven用来生成文档.

如果想要查看完整的可用元素请查阅:https://maven.apache.org/ref/3.3.9/maven-model/maven.html

现在我们回到项目,在你的第一个项目的原型生成后,你也会发现如下目录结构被创建:

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规范.想了解更多访问:http://maven.apache.org/guides/introduction/introduction-to-the-standard-directory-layout.html

现在,我们有了一个POM,一些应用代码,一些测试代码,你也许会问...

我如何编译我的应用代码

切换目录到${basedir}并执行命令:

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安装,这可能会耗费相当一会儿(在上述输出中,它耗费了四分钟).如果你再次执行这个命令,Maven就不会去下载而且可以快速执行命令.

正如你在上述输出中所看到的,编译好的class文件放在${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] ----------------------------------------------------------------------------

请注意:

1.Maven现在下载了更多的依赖.这些都是测试所需要的插件和依赖.(它已经有了编译所需的依赖所以不会再次下载)

2.在编译和运行测试之前Maven编译了main代码(所有的代码都是最新的因为我们自从上次编译后没有做任何改变)

如果你只是想要简单额编译测试代码(不运行测试),可以执行如下命令:

mvn test-compile

现在你能够编译你的应用代码,测试代码,并运行测试,你将要进行下一个逻辑步骤所以你会问...

我如何创建一个JAR并安装到本地仓库

创建JAR是相当直接的通过执行下列命令:

mvn package

如果你看下项目的POM文件你会发现packaging元素被设置为jar.这就是Maven如何知道要通过上述命令来产生JAR文件的原因.现在你可以查看${basedir}/target 目录然后你会看见生成的JAR文件.

现在你想要安装你已经生成的工件(JAR包)到本地仓库(默认地址是:${basedir}/.m2/repository).想要了解更多关于Respository请访问:http://maven.apache.org/guides/introduction/introduction-to-repositories.html

现在执行安装:

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的两倍大小.Maven还有更多的功能提供给你而不需要添加任何额外的内容到我们现在的POM中.而想在Ant中提供相同的功能你不得不添加额外的内容,而这更容易导致出错.

所以我们还能够免费得到些什么?即使是像上述这么简单的POM这里也有大量开箱即用的插件可以使用.我们会提到一个专用的Maven推崇的特性之一:不需要任何工作,POM已经有足够的信息来为你的项目生成一个Web站点.你可能想要定制你的Maven站点,但是如果你时间紧迫,那么你仅仅需要提供项目的基本信息然后执行下面的命令:

mvn site

这里还有大量独立的目标可以被执行,例如:

mvn clean

这个命令将会移除target目录在开始构建数据之前以便它是新鲜的

也许你想生成一个Intellij IDEA描述的项目:

mvn idea:idea

这可以运行在项目的前一个想法--它将更新设置而不是新的开始

如果你使用Eclipse IDE:

mvn eclipse:eclipse

注意:一些类似的目标从Maven1.0到现在一直存在,如jar:jar,但是它们的行为并不像你所期望的.目前,jar:jar不会重新编译源码,它仅仅简单创建一个JAR在target/classes目录,它假设其他一起已经完成...

什么是SNAPSHOT版本

注意:在pom.xml中的version标签的值如下所示带有后缀:-SNAPSHOT.

<project xmlns="http://maven.apache.org/POM/4.0.0"
  ...
  <groupId>...</groupId>
  <artifactId>my-app</artifactId>
  ...
  <version>1.0-SNAPSHOT</version>
  <name>Maven Quick Start Archetype</name>
  ...

SNAPSHOT值指在代码分支中的最新代码,并且不保证代码是稳定不变的.相反,RELEASE版本(任何没有SNAPSHOT后缀)是不变的.

换言之,SNAPSHOT版本是在最终发布之前的开发版.它比它的RELEASE版本要老.

在发布期间,版本从x.y-SNAPSHOT变成x.y.发布过程增加开发版到x.(y+1)-SNAPSHOT.例如:1.0-SNAPSHOT版发布成1.0版,并且新的开发版的版本为1.1-SNAPSHOT.

我如何使用插件

无论何时你想要自定义Maven项目的构建过程,它都通过添加或者重新配置插件.

Maven1.0的用户请注意:在Maven1.0中,你将添加一些preGoal到maven.xml,一些entries到project.properties.这里有一点区别.

在这个例子中,我们将配置JAVA编译器允许JDK5.0.这很简单添加到POM中:

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

你会发现所有的插件在Maven中看起来像一个依赖,而且从某种意义上来说它们确实是.插件将会被自动下载和使用,甚至包括特定的版本如果你指定了它.(默认使用最新版本)

<configuration>将应用给定的参数到每个编译插件的目标.在上述情况下,编译插件已经被作为构建过程中的一部分在使用而这仅仅是改变了配置.还可以添加新的目标到过程中,配置指定的目标.想要了解构建过程,请访问:http://maven.apache.org/guides/introduction/introduction-to-the-lifecycle.html

想找出可配置的插件,你可以查阅http://maven.apache.org/plugins/

想知道如何配置一个插件的可用参数,请查阅:http://maven.apache.org/guides/mini/guide-configuring-plugins.html

我如何添加资源到我的JAR

另一个常见用例是可以被满足的:不对我们上述的POM做任何改变就可以将资源打包进JAR.针对于这项任务,Maven仍然依靠标准目录布局,这意味着只要采用Maven标准惯例你就可以仅通过将资源放在一个标准目录结构就可以简单的将它们打包进JAR.

在我们下面的例子中你可以看见我们添加了一个用来存放任何我们想要打包进JAR的资源的目录${basedir}/src/main/resources.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

所以你可以看见在我们的例子中我们有个包含了application.properties文件的META-INF目录被放置在了指定目录 ${basedir}/src/main/resources下.如果你解压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目录下.你也会在那里发现一些其他的文件如:MANIFEST.MF,pom.xml,pom.properties等,这些是Maven中JAR包的标准生成.Maven会默认生成一个如果你没有自己创建一个manifest.(你也可以修改默认manifest中的项,稍后你会接触到).pom.xml文件和pom.properties文件被打包进JAR以便每个Maven生成的工件都是自描述的并且允许你在需要的时候在你的应用中使用元数据.一个简单的应用可能是检索应用版本.对POM的操作将会需要使用到一些Maven工具,但是可以使用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

为你的单元测试添加资源到类路径的做法和你添加资源进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中定义的一个值,可以是用户setting.xml中定义的一个值,还可以是一个外部属性文件中的一个属性甚至是系统属性.

想在拷贝时过滤资源,只需要在你的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>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
 
  <build>
    <resources>
      <resource>
        <directory>src/main/resources</directory>
        <filtering>true</filtering>
      </resource>
    </resources>
  </build>
</project>

你会发现我们添加了build,resources,resource这些之前没有的元素.此外,我们必须显示的声明资源位于src/main/resoures目录.所有我们之前提供的信息都和默认值相同,但是因为filtering的默认值是false,所以为了覆盖这个值我们要添加它到pom.xml并设置为true.

引用在pom.xml中定义的属性,属性名使用定义了相应值的XML元素名,因为根节点是project元素,所以${project.name}引用了项目的名称,${project.version}引用了项目的版本,${project.build.finalName}引用了构建项目打包后产生的文件的最终名称,等等.注意有些POM元素有默认值,所以没必要在pom.xml中显式声明它们因为它们的值是可用的.类似的,用户setting.xml中的值可以通过以"settings"打头的属性名来引用(如:${settings.localRepository}引用了用户本地仓库的路径).

继续我们的例子,让我们添加一组属性到application.properties文件中(该文件位于src/main/resources目录下),它们的值将被提供当资源被过滤时:

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

你可以执行以下命令(process-resources是构建生命周期中资源被拷贝和过滤的阶段):

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>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</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=${project.name}
application.version=${project.version}
message=${my.filter.value}

接下来执行mvn process-resources命令将会添加我们新的属性值到application.properties文件中.作为定义my.filter.value属性在外部文件中的一个替换手段,你可以在pom.xml文件中的properties元素里直接定义这个属性从而达到相同的效果.(注意:我根本不需要引用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>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</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参数定义在命令行中的.继续我们的例子,让我们做如下改变:

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

当我们再次执行mvn process-resources(注意在命令中command.line.prop属性的定义),application.properties文件将会包含来自系统属性的值:

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

我如何使用外部依赖

你可能已经发现我们在上面的例子中已经使用了dependencies元素.事实上,你已经是一直在使用外部依赖了,不过我们这里会对它的具体工作原理稍微讨论些细节.想了解更多,请自行查阅:http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

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

对于每一个外部依赖,你至少需要定义四项:groupId,artifactId,version,scope.前三项和pom.xml中用来构建项目的三个元素的含义相同.scope表明你的项目要怎么使用这些依赖,它的值可以是compile,test和runtime.要想了解所有你可以为依赖指定的详细信息,请查阅:http://maven.apache.org/ref/current/maven-model/maven.html

想了解依赖原理的所有信息,请查阅:http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html

通过这个依赖的信息,Maven将在构建项目的时候引用依赖.Maven引用的依赖从哪里来?Maven在你的本地仓库查询所有依赖.在前一章节,我们从我们的项目安装了工件 (my-app-1.0-SNAPSHOT.jar) 到本地仓库.一旦它安装到了那里,另一个项目就可以通过在pom.xml中添加依赖信息来简单的引用这个jar:

<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://repo.maven.apache.org/maven2/.你也可以设置自己的远程仓库(也许是你们公司的中央库)通过替换或者添加默认远程仓库.更多关于仓库的信息请查阅:http://maven.apache.org/guides/introduction/introduction-to-repositories.html

让我们添加另一个依赖到我们的项目中.让我们假设我们已经添加了一些日志代码并且需要添加log4j作为依赖.首先,我们需要知道log4j的 groupId,artifactId,version .我们可以浏览ibiblio来查找它,或者使用Google搜索:"site:www.ibiblio.org maven2 log4j".搜索结果显示一个目录/maven2/log4j/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文件旁边,我们可以看见一个目录对应到各个版本的log4j库.在每个目录中,我们可以找到实际的jar文件和pom文件和另一个maven-matedata.xml文件.这里还会有对应的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>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</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依赖.

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

为了部署jars到一个外部仓库,你必须在pom.xml中配置仓库的URL并在settings.xml认证连接仓库的信息.

这里有个使用SCP,用户名/密码认证的例子:

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>
  <version>1.0-SNAPSHOT</version>
  <packaging>jar</packaging>
 
  <name>Maven Quick Start Archetype</name>
  <url>http://maven.apache.org</url>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</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.xml:

<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> (default is ~/.ssh/id_dsa)
      <passphrase>my_key_passphrase</passphrase>
    </server>
  </servers>
  ...
</settings>

请注意,如果你连接的服务器是openssh这样的ssh服务器,并且它sshd_config文件中的参数"PasswordAuthentication"设置为"no",那么你每次连接都需要输入用户名密码来进行验证.(尽管你可以使用另一个ssh客户机来输入用户名密码进行登录).所以可能想要切换成公钥验证.

如果在settings.xml中使用密码我们应该保持谨慎.更多信息查阅:http://maven.apache.org/guides/mini/guide-encryption.html

我该如何创建文档

让我们开始Maven的文档系统,你可以使用原型机制来为你的项目生成站点通过如下命令:

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

访问以下链接来学习如何为你的项目生成文档:http://maven.apache.org/guides/mini/guide-site.html

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

注意:生命周期应用于任何项目类型.例如,返回基础目录我们可以创建一个简单的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>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>
 
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
 
  <build>
    <finalName>my-webapp</finalName>
  </build>
</project>

注意<packaging>元素,它告诉Maven把项目构建成WAR.切换到webapp项目目录执行:

mvn clean package

你将会看见target/my-webapp.war已经被创建,并且所有的步骤都已经被执行.

我如何一次构建多个项目

处理多个模块的概念是建立在Maven之上的.在这个章节,我们将会展示如何用一个步骤构建war包的同时包含之前的jar包.

首先,我们需要在上述两个目录外添加一个父级pom.xml,结构看起来像这样:

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

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>app</artifactId>
  <version>1.0-SNAPSHOT</version>
  <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的<packaging>元素的值是"pom"并且定义了<modules>来罗列所有子模块.这告诉Maven在所有子项目上执行所有操作而不是在当前项目上.(使用非递归选项--non--recursive来覆盖命令的行为).

然后,我们告诉WAR它需要my-app的JAR.这做了一些事情:它让WAR中的所有代码在类路径中都可用,它确保JAR包在WAR包之前被构建,它表明了JAR作为插件添加到了WAR的类库目录.

你也许已经发现junit-4.11.jar是一个依赖,但是没有出现在WAR包中.这是因为它的<scope>的值是"test",表明仅仅在测试时需要使用.所以他不会在编译的时候添加进来.

最后一步是包含父级定义.这和你可能熟悉的Maven1.0中的extend元素不同:这确保通过在仓库中查询POM总是可以被放置即使项目是分布式的.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!