原文:
http://maven.apache.org/guides/introduction/introduction-to-the-pom.html
本文基本上是翻译+一点点理解。
POM(Project Object Model) 是Maven的基础。它是一个XML文件,包含了Maven用来build项目所需要的项目配置的信息。
(译者:在使用ant进行build时,我们需要通过script告诉ant每一步要做什么,同时提供每一步需要的信息。
例如,首先要编译,编译的源代码在哪里,目标代码放哪里等等。
在Maven中我们不需要告诉Maven应该做些什么,仅需要在pom中提供一些必要的信息即可。对于那些在pom中没有提到的信息,Maven就会使用默认值。
例如Maven默认源代码在src/main/java中。因此Maven在最大程度上简化了项目build的过程。)
它包含了可用于大部分项目的默认值。例如,build directory默认使用<target>定义;source directory,默认使用了src/main/java;test source directory默认使用了src/main/test等等。
在Maven1中(Maven的早期版本)POM的名字是project.xml,而在Maven 2中改为pom.xml。
(译者:通常认为Maven从1到2发生了根本性的改变,因此尽管可能你使用的Maven是3.x的版本,仍然会发现很多以m2命名的目录。)
同时,以前在maven.xml中包含的goal,plugin等信息现在也被放到了pom.xml中。当执行一个task或goal时,Maven搜索当前目录下的pom文件,从其中取出需要的配置信息并执行goal。
(译者:plugin和goal的概念非常重要,请参考我的另外一篇介绍Maven中的lifecycle的文章。)
(译者:文中分别写出了Maven2.0.x和2.1.x的super POM的具体内容。这里请参考原文)
一个最简单的POM文件需要包括的内容如下:
(译者:也就是说,如果想建立一个简单的Maven项目,提供一个如此简单的POM就够了。Maven会自动完成剩下的事情)
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
一个POM必须配置项目的groupId, artifactId, 和version。这三个值构成了项目的fully qualified artifact name。那就是<groupId>:<artifactId>:<version>。对于上面的例子,fully qualified artifact name就是“com.mycompany.app:my-app:1”
同时,正如在第一节提到的,如果一些配置信息没有被提供,Maven将会使用默认值。这些默认值之一是packaging type。如果POM中没有配置它,将会使用默认值jar。
此外,如同你在最简单的POM中看到的,这个POM并没有配置所使用的repositories。
(译者:repository是Maven中的另外一个重要概念,不清楚的同学请参考我的另外一篇关于Maven中repository的文章。)
如果你使用这个POM来build你的项目,它将从Super POM继承repository的配置。因此,当Maven发现需要下载POM中的dependency时,它会到Super POM中配置的默认repository,http://repo1.maven.org/maven2去下载。
(译者:project inheritance 和下面要提到的project aggregation 是理解项目间POM父子关系的关键,必须理解。)
另外一些可包含在POM中的信息是:
其实Super POM就是项目继承的的一个例子。然而你同样可以通过在POM中加入<parent>,来引入其他的父POM。
示例一:
在前面的例子中我们已经引入了“com.mycompany.app:my-app:1”这个项目,现在我们再引入另一个项目“com.mycompany.app:my-module:1”并以此为例,讲述如何让my-app成为my-module的父项目。
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
同时让它们的目录结构如下:
.
|-- my-module
| `-- pom.xml
`-- pom.xml
my-module/pom.xml 指的是my-module这个项目的POM,而pom.xml指my-app的POM。
现在,我们把my-module的POM修改成下面:
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
注意现在我们加了一个配置,parent。这个配置允许我们设置哪个项目(artifact)是当前项目的父项目。我们需要设置父POM的fully qualified artifact name。配置好之后,my-module的POM就可以从my-app的POM中继承一些配置信息了。
另外,如果我们希望my-module的groupId和/或version与父项目保持一致,我们甚至可以删除my-module的POM中的groupId和/或version。
示例二:
然而上例是有局限性的。只有当父项目已经安装到local repository中,或者必须是特殊的文件结构(父项目的pom.xml在子项目的pom.xml的父一级目录里)时,上例才工作。
(译者:我工作的就是类似的父子项目。子项目依赖于父项目。每次修改了父项目的代码后,必须运行:
mvn install //将父项目编译并加入到repository中
之后才能顺利的运行子项目。)
如果父项目没有安装到local repository中,同时目录结构如下(父子项目在平行的目录结构中)就会有问题:
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
为了解决这个目录结构(也可以是其他目录结构)导致的问题,我们必须在parent section中使用<relativePath>。
<project>
<parent>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<relativePath>.../parent/pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>my-module</artifactId>
</project>
如同<relativePath>的字面意思(相对路径),它是module的pom.xml到父pom.xml的相对路径。
project aggregation 和project inheritance类似。但与project inheritance在my-module中设置父POM不同的是,project aggregation是在父POM中设置my-module。
通过这种方式,父项目在知道它的子模块。同时,如果在父项目上执行Maven命令,父项目和所有的子模块都会执行该命令。
(译者:这就是为什么在Maven的POM中既有父子关系,又有子父关系。)
要使用project aggregation, 必须:
1, 将父POM的<packaging>改为“pom”。
2, 在父POM中设置子模块的路径。
示例三:
再次使用之前的pom示例和目录结构,如下:
com.mycompany.app:my-app:1's POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
</project>
com.mycompany.app:my-module:1's POM
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-module</artifactId>
<version>1</version>
</project>
目录结构:
.
|-- my-module
| `-- pom.xml
`-- pom.xml
如果我们想把my-module加到my-app中,可以简单的讲my-app的pom.xml改为如下:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>my-module</module>
</modules>
</project>
<module>的值是从com.mycompany.app:my-app:1的pom到com.mycompany.app:my-module:1的pom的相对路径(在例子中使用module的artifactId,即my-module作为目录名,所以<module>设置的不是module名,而是目录的名字)。
现在,对于my-app运行的任何一个Maven命令(或者说phase或goal),同时也会在my-module上运行。
示例四:
但是如果我们将目录改为:
.
|-- my-module
| `-- pom.xml
`-- parent
`-- pom.xml
父pom应该怎么设置呢?
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycompany.app</groupId>
<artifactId>my-app</artifactId>
<version>1</version>
<packaging>pom</packaging>
<modules>
<module>../my-module</module>
</modules>
</project>
答案是,使用和实例三同样的方法,将路径加到<module>中。
如果你有好几个Maven项目,同时它们有着类似的配置信息,你可以重构你的这些项目,通过将这些相同的配置抽取出来,放到一个父项目中去。
这样,你需要做的所有事情就是让你的Maven项目继承父项目,然后这些共同的配置就会生效了。
同时,如果你有一组项目,它们需要在一起build和process,你可以创建一个父项目,同时将这些子项目配置成父项目的modules。通过这种方式,你只需要build父项目而子项目就都会build了。
(译者:例如我工作的项目,多个项目,比如项目A,B,C共享同样的核心代码。采取的方式就是将核心代码抽取出来做成一个父项目称为core,将)这些项目配置为父项目的modules。
可以通过build core项目,就build了所有的modules。
但有时也需要变通一下:当运行比如A项目的daily build时,我们并不需要build所有的项目。这时的做法就是,对于core项目,实际有4个pom文件:
pom.xml, A_pom.xml, B_pom.xml, C_pom.xml。当运行A的daily build时,实际在build环境中使用的是A_pom.xml。同时该pom文件中,core的子模块只有A一个。
另外需要注意的一点是:如何build的问题
例如我前面提到的我工作的项目,如果修改了core中的代码,并想重新build项目A时,有三种方法。
1,在core项目上运行mvn build。这样core, A, B, C4个项目都会被build。
2,如果只想build项目A,就用A_pom.xml覆盖core的pom文件,然后运行mvn build。则会build项目core和A。
3,或者,对core项目运行mvn install(该命令会编译,build并将build出来的jar包安装到repository中去), 之后再在A项目运行mvn build)
但是,当然了,你也可以同时使用项目集成和项目继承。意思是,你可以在子项目的pom中配置parent,同时在父项目中配置modules。你只需要明确下面3个规则:
1, 在每一个子项目pom中都要配置parent。
2,将父项目pom的packaging改为“pom”。
3,在父pom中配置子modules。
(译者:到此项目间的关系已经讲完了,让我们来总结一下:
当我们拿到了几个相关项目时,一定要先搞清楚这些项目间的父子关系。我们不仅要考察每一个项目的pom文件,弄清楚他们之间的集成和继承关系,也需要留意项目的目录结构,以防止有些设置并没有生效。
只有弄清楚了项目的关系,我们才能正确的使用Maven的功能)
(译者:原文中还有一个示例五,是关于将上面3点都融合在一起的pom文件,我觉得没有必要再累述了。)
(另外需要说明的一点,如果打开本地的repository,你会发现每个artifact(通常是jar包)也有自己的pom文件。其实原因很简单:Maven也要管理这些artifact。比如类库A,同时也依赖于类库B,C。
因此repository中的artifact也需要pom文件来说明它们之间的关系)
Maven鼓励的一种做法是,不要自我重复。然而,有时候还是需要在几个不同的地方使用相同值。为了保证仅在唯一的地方定义值,Maven允许你在pom中使用你自己定义的变量。
例如,为了在pom几个不同的地方使用相同的值,project.version,你可以这样做:
<version>${project.version}</version>
同时,在pom文件中定义:
<project>
...
<properties>
<version>1.0.4</version>
</properties>
...
</project>
需要注意的是,这些变量是在继承机制生效后赋值的。这意味着,如果一个父项目pom包含变量,这些变量会被子项目继承并可以在子项目中直接使用。
这里有三种可使用的变量:
所有在pom中的独立的element都可以作为一个变量。例如${project.groupId},${project.version},${project.build.sourceDirectory} 等等。参考POM reference来得到所有的properties。
所有这些变量使用时都应加上前缀"project."。你也可能看到一些以“pom.”为前缀的情况,但是已经不赞成这么做了。
basedir | The directory that the current project resides in. |
project.baseUri | The directory that the current project resides in, represented as an URI.Since Maven 2.1.0 |
maven.build.timestamp | The timestamp that denotes the start of the build. Since Maven 2.1.0-M1 |
对于build timestamp的格式问题,可以通过<maven.build.timestamp.format>指定,如下:
<project>
...
<properties>
<maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
</properties>
...
</project>
日期格式需要遵守的规则可以参考 SimpleDateFormat(java的)的API文档。如果没有设置这个值,则使用上例中的默认值。
最后一种就是前面提到的<properties>,不累述。
原文到此结束,但我还想加一点关于POM中的dependency的内容。
dependency描述了当前项目对其他项目的依赖关系。如下例,表示当前项目依赖于log4j artifact(并非父子关系)。
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.14</version>
</dependency>
</dependencies>
同样我们使用的很多第三方工具,如JUnit等等,都需要使用dependency加入到项目的POM中(当然也可以使用项目继承的方法,从父项目继承)。
在eclipse中使用Maven插件时,可以使用图形化界面添加dependency。过程是:
1,点击添加dependency。
2,输入名字,如JUnit。此时Maven插件会到使用的remote repository中搜索相应的类库。
3,搜索到以后,点击希望添加的artifact,确定。此时POM文件已经被修改了,加入了新增的dependency。
4,点击保存。这时Maven就会开始从remote repository下载artifact。
如果没有按照Maven插件,另外一种方法就是直接修改pom.xml,加入dependency部分。保存后Maven即开始下载artifact。
不过这里有一个问题,直接修改pom.xml时,往往不知道要添加的类库的完整名称,即<groupId>:<artifactId>:<version>,进而也不知道该怎么填写<groupId><version>等内容。
这里有一个方法,下面的网站是browse repository的:
https://repository.sonatype.org/index.html#nexus-search;quick~junit
使用方法类似:搜索后,找到想要的类库,然后就能看到对应的 <dependency>的内容。直接将该段xml复制到自己的pom.xml中就可以了。
完毕~~~
关于POM,可以参考http://maven.apache.org/pom.html 得到更详细的解释。
看完了Maven中的几个重要概念一,二和三,相信对Maven已经有比较全面的了解了。
这个时候开始看Maven的完全参考手册就会非常轻松了。