Maven用户指南(1)

Maven最早始于Jarkarta Turbine项目,目的是为了简化构建过程。这个项目下面有 几个子项目,每个子项目都有自己的Ant文件,但是区别很小,而且生成的JAR 文件都要check in到CVS中。我们希望有一种标准的方式来构建这些项目,一种可以 清晰描述项目的方式,一种易于发布项目信息的方式,一种在多个项目之间共享JARs 的方式。

这个结果就是产生了一个可以用于构建、管理任何基于java的项目。我们希望我们创造 的这个工具可以让Java开发者的日常工作更加轻松,并有助于理解基于java的项目.

项目对象模型
Maven是基于项目对象模型(POM)的概念而创建的。在这个模型中,所有由Maven产生的 artifact都是清晰定义的项目模型的结果。构建,文档,源码度量,源码交叉引用和其他 任何由Maven plug-in提供的东西都是由POM来控制的。

POM 处理机制
这篇文档简单的描述了Maven执行过程中是如何处理POM的。这里有一些简单的POM例子 来展示继承机制和插值机制。

POM 插值机制
POM(通常以project.xml的名字出现)现在已经被当作Jelly脚本来处理了。大部分时 候,用户无须关心project.xml文件是不是真正的Jelly脚本,但是,如果需要的话, 也可以使用内置值。我也不愿看到逻辑控制语句出现在project.xml中,但是由于 project.xml实际上已经是一个隐含的jelly的脚本,所以它会有足够的灵活性:-)。 下面是一个简单的例子。

<?xml version="1.0" encoding="ISO-8859-1"?>
<project>

  <pomVersion>3</pomVersion>
  <groupId>maven</groupId>
  <artifactId>maven</artifactId>
  <name>Maven</name>
  <currentVersion>1.0-b5-dev</currentVersion>
  <organization>
    <name>Apache Software Foundation</name>
    <url>http://jakarta.apache.org/</url>
    <logo>/images/jakarta-logo-blue.gif</logo>
  </organization>
  <inceptionYear>2001</inceptionYear>
  <package>org.apache.${pom.artifactId}</package>
  <logo>/images/${pom.artifactId}.jpg</logo>

  <description>Maven is a project that was created in ${pom.inceptionYear}.</description>
  <shortDescription>${pom.name} is a Java Project Management Tool</shortDescription>

</project>
        POM 继承机制
现在有一种简单方式可以用于在POM中进行继承,下面是一个简单的例子:

<?xml version="1.0" encoding="ISO-8859-1"?>
  <project>
    <extend>project.xml</extend>
   
    <groupId>super-extendo</groupId>
    <artifactId>super-extendo<artifactId>
    <name>Super Extendo</name>

    <build>
      <unitTest>
        <includes>
          <include>**/*Test*.java</include>
        </includes>
        <excludes>
          <exclude>**/TestAll.java</exclude>
          <exclude>**/*Abstract*.java</exclude>
        </excludes>
      </unitTest>
    </build>
  </project>
目前对POM父对象的解析还相对较弱,现在对一层以上的继承还没有做过任何测试。尽管如此, 单层继承加上插值机制已经能够给带来很多好处。这些机制的意图在于简化构建的共用问题。

你可以这样定义主模板:

<project>
  <pomVersion>3</pomVersion>
  <groupId>commons</groupId>
  <artifactId>commons-master</artifactId>
  <name>Commons Master Maven POM</name>

  <organization>
    <name>Apache Software Foundation</name>
    <url>http://www.apache.org</url>
  </organization>

  <gumpRepositoryId>jakarta</gumpRepositoryId>

  <url>http://jakarta.apache.org/commons/${pom.artifactId}.html</url>
  <issueTrackingUrl>http://nagoya.apache.org/</issueTrackingUrl>
  <siteAddress>jakarta.apache.org</siteAddress>
  <siteDirectory>/www/jakarta.apache.org/commons/${pom.artifactId}/</siteDirectory>
  <distributionDirectory>
    /www/jakarta.apache.org/builds/jakarta-commons/${pom.artifactId}/
  </distributionDirectory>

  <repository>
    <connection>
      scm:cvsserver:anoncvs@cvs.apache.org:/home/cvspublic:jakarta-commons/${pom.artifactId}
    </connection>
    <url>http://cvs.apache.org/viewcvs/jakarta-commons/${pom.artifactId}/</url>
  </repository>
  ...
</project>
子POM对象可以这样定义:

<project>
  <groupId>commons-betwixt</groupId>
  <artifactId>commons-betwixt</artifactId>
  <name>Betwixt</name>
  ...
</project>
这样你就可以在父POM对象中,将子POM对象的${pom.artifactId}替换进去。有许多项目的 构建都以相似的方式进行构建,这样一来,对于项目的公共部分,你就可以使用一个主模板, 然后在子POM对象project.xml中定义有区别的部分,而这部分内容通常很少。

这种机制确实还可以简化那些需要产生多个JAR包的项目。由于project.xml和标准Ant构建 不会相互干扰,我计划在公共部分测试继承机制。

如果你对使用这种机制,DVSL报告会变成什么样感到疑惑,我要说,你很上路。我已经修改 了DVSL报告来适应POM本身,这就是说DVSL转换是基于java对象的。在使用继承和插值机制的 时候,为了正确的产生DVSL报告,这是很有必要的。象上面列出的子模板是无法工作的,我们 需要全面的解析POM。我能说的是,它可以工作了!我所使用的处理方式可能不是最有效率的 方式,但仍有提升的空间。因为POM只会被处理一次(不管怎么说,这就它的原理,我可能漏了 某些东西),然后到处使用,至少这就是我以前试图做的事情,所以我们很有可能会取得平衡。

如果你不使用继承和插值,那么一切照常工作。maven站点本身一切ok,有几个刚部署的站点 已经使用了我昨晚提交的东西了。

使用插件
Maven是一个很紧凑的内核,围绕着它的是许许多多的插件。Maven所有的功能都是由插件来提供 的。

maven.xml文件
项目中的maven.xml文件是Maven在执行过程中要使用的“定制”文件。

在这个文件中,你可以加入Maven构建中需要的额外处理。或者在Maven的“目标”前后附加自己 的代码,如jar 或 test。

Maven使用Jelly 脚本语言, 任何合法的jelly标签都可以在maven.xml中使用。

Maven所采用的goal功能是由werkz标签库提供。更多的信息请看 wiki页面.

简单的maven.xml例子
注意由于Maven并未缺省的定义'compile'目标,下面这个例子没法运行。

这是一个简单的maven.xml例子

<project
  default="nightly-build"
  xmlns:j="jelly:core"
  xmlns:u="jelly:util">

  <goal name="nightly-build">
    <!-- Any ant task, or jelly tags can go here thanks to jeez -->
    <j:set var="goals" value="compile,test" />
    <mkdir dir="${maven.build.dir}" />
    <u:tokenize var="goals" delim=",">${goals}</u:tokenize>
    <j:forEach items="${goals}" var="goal" indexVar="goalNumber">
      Now attaining goal number ${goalNumber}, which is ${goal}
      <attainGoal name="${goal}" />
    </j:forEach>
  </goal>

</project>
你可能会注意到这里一些有意思的东西,下面我们将逐一解释。

project节点
project节点, &lt;project&gt;, 是任何 maven.xml 文件的根节点。

项目节点有一个缺省的属性:default="nightly-build",如果用户只是简单键入 没有参数的maven命令,Maven就会用nightly-build 目标作为缺省目标。

接下来是几个名字空间的声明,如:

xmlns:j="jelly:core"
所有以j:作为前缀的节点,Jelly都会把它视为在core标识下 预定义的标签库。

xmlns:u="jelly:util"
所有以u:作为前缀的节点,Jelly都会把它视为在标识下 预定义的标签库。


所有在maven.xml文件使用的Jelly标签库,都必须在project节点中定义,并且 分配一个名称空间前缀。

Maven已经预先包含了jeez标签库作为空前缀。这个标签库在一个名称空间内包含了 ant 和 werkz 标签库。这样,任何werkz或ant标签都无须名称空间 即可使用,同时也简化了ant的迁移过程。

目标
goal是一个 werkz 标签,类似于Ant的target;它是包含了一系列可执行标签的容器。

由于jeez 标签库已经由maven预先注册了,一个目标(goal)可以包含任何合法的 Ant 标签。

为了执行在maven.xml中定义的目标,你只需要在命令行中为Maven指定目标名即可。要执行例子中定 义的nightly-build你只需执行命令:

maven nightly-build
Maven插件定义的目标需要在目标前加上插件名,这样一来,就不会和你自己的goal冲突,如 jar:jar就是 jar 插件定义的目标,用于创建项目的jar包。

Jelly编程
在每个目标里,由Jelly标签提供功能,让我们来看看例子里的这些代码。

set
<j:set var="goals" value="compile,test" />这行就是一个jelly的core标签set,它使用了project节点中定义的前缀 j:

set标签设置了一个由var属性定义的Jelly变量,值由 value 指定。和Ant的proerties不一样,Jelly变量在被赋值后仍可以改变。

mkdir
<mkdir dir="${maven.build.dir}" />等同于Ant任务 mkdir, 用于创建目录,目录名由变量 ${maven.build.dir}指定。

tokenize
<u:tokenize var="goals" delim=",">${goals}</u:tokenize>这行执行的是Jelly tokenize 标签。这是Jelly util 标签库中标签, 这个标签库已经在项目节点中预先定义:u:

tokenize标签在将节点中的内容分离成一个list,用于后续的处理。

var 属性就是将被于新list的变量。
delim 属性是用于分割字符串中的分隔符。
在这个例子中,tokenize 标签中节点值是一个变量:goals, 在前几行中,这是一个由逗号分隔、compile 与 test 的字符串。

forEach
<j:forEach items="${goals}" var="goal" indexVar="goalNumber">
  Now attaining goal number ${goalNumber}, which is ${goal}
  <attainGoal name="${goal}" />
</j:forEach>forEach标签提供简单循环功能,节点值就是循环体。

items 属性是一个表达式,是在循环过程中需要遍历的值集合。
集合中的值被逐个取出,存放在var 属性指定的变量中。你可以在 forEach 循环体访问这个变量。
indexVar 属性指定了一个计数器(起始基数为0)变量,用于在处理 过程中计数。

forEach 标签的节点值输出了一些在处理过程中的关于目标的文本,并使用 attainGoal werkz 标签来获得(执行?)这些目标。 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值