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的脚本,所以它会有足够的灵活性:-)。 下面是一个简单的例子。




  3
  maven
  maven
  Maven
  1.0-b5-dev
  
    Apache Software Foundation
    http://jakarta.apache.org/
    /images/jakarta-logo-blue.gif
  

  2001
  org.apache.${pom.artifactId}
  /images/${pom.artifactId}.jpg

  Maven is a project that was created in ${pom.inceptionYear}.
  ${pom.name} is a Java Project Management Tool


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


  
    project.xml
   
    super-extendo
    super-extendo
    Super Extendo

   
      
        
          **/*Test*.java
        

        
          **/TestAll.java
          **/*Abstract*.java
        

      

   

  

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

你可以这样定义主模板:


  3
  commons
  commons-master
  Commons Master Maven POM

  
    Apache Software Foundation
    http://www.apache.org
  


  jakarta

  http://jakarta.apache.org/commons/${pom.artifactId}.html
  http://nagoya.apache.org/
  jakarta.apache.org
  /www/jakarta.apache.org/commons/${pom.artifactId}/
  
    /www/jakarta.apache.org/builds/jakarta-commons/${pom.artifactId}/
  


  
   
      scm:cvsserver:[email protected]:/home/cvspublic:jakarta-commons/${pom.artifactId}
   

    http://cvs.apache.org/viewcvs/jakarta-commons/${pom.artifactId}/
  

  ...

子POM对象可以这样定义:


  commons-betwixt
  commons-betwixt
  Betwixt
  ...

这样你就可以在父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例子

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

  
   
   
   
    ${goals}
   
      Now attaining goal number ${goalNumber}, which is ${goal}
      
   

  



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

project节点
project节点, <project>, 是任何 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
这行就是一个jelly的core标签set,它使用了project节点中定义的前缀 j:

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

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

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

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

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

forEach

  Now attaining goal number ${goalNumber}, which is ${goal}
  
forEach标签提供简单循环功能,节点值就是循环体。

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

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

你可能感兴趣的:(Java开源技术)