空间站

北极心空

  BlogJava :: 首页 :: 联系 :: 聚合  :: 管理
  15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks
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  标签来获得 ( 执行 ?) 这些目标。  

Maven 
配置
属性的处理机制
Maven
按下面的顺序依次读入 properties 文件:  


${project.home}/project.properties 
${project.home}/build.properties 
${user.home}/build.properties 

读入的属性遵循 最后的定义有效 原则。也就是说, Maven 依次读入 properties 文件,以新的定义   覆盖旧的定义。 ${user.home}/build.properties Maven 最后处理的文件。我们把   这些文件称为 Maven 处理的标准属性文件集。  

另外,上述 properties 文件处理完毕后, Maven 才会开始处理系统属性。所以,如果在命令行中使用   -Dproperty=value 这样的形式来指定的属性,它会覆盖先前定义的同名属性。  

插件的属性
上述属性文件处理完后, Maven 才会开始调用插件,但是  PluginManager  会禁止插件   覆盖已经设置的属性值。这和 Maven 一般的属性处理方式是相反的,这是因为插件只能在 Maven 内部的   其他部分初始化完毕后才能处理,但是我们又希望以这样顺序去处理属性:  


处理 Plug-in  缺省属性  
处理 ${project.home}/project.properties 
处理 ${project.home}/build.properties 
处理 ${user.home}/build.properties 

这样一来,即使插件处于属性处理链的后端,也能覆盖插件的任何缺省属性。例如, Checkstyle 插件   就定义了如下缺省属性:  

maven.checkstyle.format = sun
你可能已经猜出来了, Checksytle 插件把 Sun 的编码规范作为缺省的格式。但是我们仍然可以在标准属性   文件集的任何一个文件中覆盖这个属性。所以如果在 ${project.home}/project.properties  文件定义了如下属性值:  

maven.checkstyle.format = turbine
Checkstyle
就会使用 Turbine 的编码规范。  

行为属性
下面的这些属性可以改变 Maven 行为方式  

属性   描述   缺省值  
maven.build.dest 
目录名,存放编译生成的类   ${maven.build.dir}/classes 
maven.build.dir 
存放构建结果的目录,如类文件,文档,单元测试报告等等。  
注意:   ${user.home}/build.properties 文件中改变 maven.build.dir  的缺省值或许会得到一个   较为个性化的目录布局。但是,这会干扰 Maven 由从源码开始的编译工作,因为它假设 jar   会被创建到 ${basedir}/target/ 目录中。  
 ${basedir}/target 
maven.build.src 
源码目录   ${maven.build.dir}/src 
maven.conf.dir 
配置文件目录   ${basedir}/conf 
maven.docs.dest html
格式报告的输出目录   ${maven.build.dir}/docs 
maven.docs.omitXmlDeclaration 
产生的文档所应包含的 xml 声明头,如:  
<?xml version="1.0"?> false 
maven.docs.outputencoding 
生成文档的缺省编码   ISO-8859-1 
maven.docs.src 
用户提供的文档目录   ${basedir}/xdocs 
maven.gen.docs xdocs
文档转换成 html 后的输出目录   ${maven.build.dir}/generated-xdocs 
maven.home.local maven
用于写入用户信息的本机目录,如解开插件包、缓冲数据。   ${user.home}/.maven 
maven.mode.online 
是否连接 internet  true 
maven.plugin.dir 
插件的存放目录   ${maven.home}/plugins 
maven.plugin.unpacked.dir 
用于展开安装插件的目录   ${maven.home.local}/plugins 
maven.repo.central 
在进行 dist:deploy 处理的时候,发行包所要部署的目标机器   login.ibiblio.org 
maven.repo.central.directory 
在进行 dist:deploy 处理的时候,发行包所要部署的目标目录。   /public/html/maven 
maven.repo.local 
本机 repository ,用于存储下载的 jar 包。   ${maven.home.local}/repository 
maven.repo.remote 
远程 repository ,如果本机 repository 没有的 jar 包, maven 会从这里下载。   http://www.ibiblio.org/maven  
maven.repo.remote.enabled 
是否使用远程 repository   true 
maven.scp.executable 
用于安全拷贝的可执行程序   scp 
maven.src.dir 
基础源代码目录   ${basedir}/src 
maven.ssh.executable 
远程命令可执行程序   scp 


使用代理
如果你只能通过代理访问,不要紧, Maven 为你提供了下列属性:  

代理属性   描述  
maven.proxy.host 
代理的 IP 地址   
maven.proxy.port 
代理端口   
maven.proxy.username 
如果代理需要认证的话,在这里填写用户名。  User name if your proxy requires authentication.  
maven.proxy.password 
如果代理需要认证的话,在这里填写密码。   

如果你实在需要代理,最好在 ${user.home}/build.properties 文件中指定。  

## ----------------------------------------------------------
## ${user.home}/build.properties
## ----------------------------------------------------------
.
.
maven.proxy.host = my.proxyserver.com
maven.proxy.port = 8080
maven.proxy.username = username
maven.proxy.password = password
.
.
使用多个远程 Repositories
你可以在任何 Maven 可以处理的属性文件中指定使用多个远程 Repositories ,如:  

maven.repo.remote = http://www.ibiblio.org/maven /,http://www.mycompany.com/maven/
项目设置
开始一个新项目
如果你是第一次使用 Maven ,或者开始一个新的项目,你可以使用 GenApp 来自动创建 Maven 项目树。  

maven -Dpackage=com.mycompany.app genapp
执行该命令后,屏幕显示如下:  

 __  __
|  \/  |__ Jakarta _ ___
| |\/| / _ \ V / -_) ' \  ~ intelligent projects ~
|_|  |_\__,_|\_/\___|_||_|   v. 1.0-beta-9


    [mkdir] Created dir: <target-directory>/genapp/src/java/com/mycompany/app
    [copy] Copying 1 file to <target-directory>/genapp/src/java/com/mycompany/app
    [mkdir] Created dir: <target-directory>/genapp/src/test/com/mycompany/app
    [copy] Copying 3 files to <target-directory>/genapp/src/test/com/mycompany/app
    [copy] Copying 2 files to <target-directory>/genapp
    [copy] Copying 1 file to <target-directory>/genapp/src/conf
    BUILD SUCCESSFUL
    Total time:  3 seconds
执行完毕,即生成下面的完整项目目录树:  

.
|-- project.properties
|-- project.xml
`-- src
    |-- conf
    |   `-- app.properties
    |-- java
    |   `-- com
    |       `-- mycompany
    |           `-- app
    |               `-- App.java
    `-- test
        `-- com
            `-- mycompany
                `-- app
                    |-- AbstractTestCase.java
                    |-- AppTest.java
                    `-- NaughtyTest.java

构建
Maven
采用了集中管理库的理念。所有用于构建的 jar 包都是从集中管理的中心库上取出。目前,   我们的中心库放在这儿  Ibiblio.  在一个典型的 Maven 项目中,构建所需的  jar 包会从中心库下载。 Maven 只会取回依赖链条上缺失的包。如果你使用 Maven 来构建几个项目,   这些项目可能会共享一些依赖包: Maven 可以在任意个项目中共享同一个包,而无须在同一系统   中保持一个 jar 包的多个拷贝。  

构建生命周期

CVS 中存放 jar 文件
我们不推荐你在 CVS 中存放 jar 包。 Maven 提倡在本机 repository 中存放用于构建共享的 jar 包或   和其他项目包。许多项目都依赖于诸如 XML 解析器、标准例程,这在 Ant 构建中,经常会被复制   多份。在 Maven 中,这些标准例程就存放在本地 repository 中,供任何项目构建使用。  

重载已声明的依赖包
你可能会发现,在某些情况下允许重载 POM 中已经声明的依赖包会很方便,甚至很有必要。   你可能会希望使用文件系统中的某个 JAR 包,或者你希望简单重新指定某个包的版本。对于   这样的情况, Maven 提供了一种简单的方式,允许你选择构建所需的 jar 包。我们严重建议   你设置本机 repository ,但是在简单至上,或在由 ant 构建迁移的情况下, JAR 包重载特性   会显得非常方便。  

为了使用 JAR 包重载特性,你必须将 maven.jar.override  属性设置为  on   只要设置了这个属性,就可以在任何 maven 处理的属性文件中重载 JAR 包。  

关于 JAR 重载的指令有两种。第一种允许你指定某个特定的包的路径,作为 JAR 包;的二种   允许你指定某个特定的 JAR 包(这个 jar 包必须已经存在于本机 repository )。下面是这两   种方式:  


maven.jar.artifactId = [path]

maven.jar.artifactId = [version]

下面是一个使用 JAR 重载指令的属性文件例子:  

# ------------------------------------------------------------------------
# M A V E N  J A R  O V E R R I D E
# ------------------------------------------------------------------------
maven.jar.override = on

# ------------------------------------------------------------------------
# Jars set explicity by path.
# ------------------------------------------------------------------------
maven.jar.a = ${basedir}/lib/a.jar
maven.jar.b = ${basedir}/lib/b.jar

# ------------------------------------------------------------------------
# Jars set explicity by version.
# ------------------------------------------------------------------------
maven.jar.classworlds = 1.0-beta-1
使用 SNAPSHOT 依赖
Maven 中, SNAPSHOP 是某个特定项目的最新构建的 jar 包。如果你的项目依赖于另一个频繁变更   的项目,你可以在你的 POM 中声明 SNAPSHOP 依赖,以保持与那个项目的同步。例如,在你的 POM   这样写,你可以与 Jelly 保持   同步更新。  

<project>
  ...
  <dependencies>

   <dependency>
     <groupId>commons-jelly</groupId>
     <artifactId>commons-jelly</groupId>
     <version>SNAPSHOT</version>
   </dependency>

  </dependencies>
 ...
</project>
上述语句的含义是:总是使用 Maven repository 中最新的 Jelly 构建包。 SNAPSHOT 依赖   总会导致依赖失败。在这种情况下, Maven 就会去 Maven repository 取得一个 SNAPSHOT  依赖包的拷贝。如果你正在离线工作, Maven 就会发出警告: “SNAPSHO 依赖包可能已经   过期  

多项目构建和 Reactor
Maven 中, Reactor 是一个用于控制多项目构建的工具。 Reactor Werkz , 并根据每个项目   各自定义的依赖关系来安排构建顺序。 Reactor 的意图在于:鼓励创建 / 重构具有更小、更松散、   更有一致性单元的项目。 r 源于面向组件编程,在向组件编程中,整个系统由许多松散的个体   构成,这些个体需要聚合起来作为一个整体进行部署。  

Reactor
可以为某个项目集执行一个任意编排的目标列表。所以,如果使用 Reactor 的话,它   可以用来做项目站点生成,任意 jar 包生成这样的事情。  

目前  db.apache.org  站点就是收集了其子项目的   丰富信息、并与一系列的 Velocity  模板合成的。这一过程是由  Jelly Velocity  标签库来完成的。   这里是其中的机制,有兴趣可以看看。  

Plexus(
一个基于 Avalon 的容器 ) 组件的 manifest 是遍历所有 Plexus 组件、并聚合而成的。这里   使用的还是 Velocity 模板和 Jelly Volocity 标签库。   这里是其中的机制,有兴趣可以看看。  

这里是一个使用 Reactor 标签,遍历一系列组件,最后产生项目站点的例子:  

  <goal
    name="project-site"
    description="Generate the site for the entire project">

    <!-- Generate the site for each of the components. -->

    <maven:reactor
      basedir="${basedir}/components"
      postProcessing="true"
      includes="*/project.xml"
      excludes="bad-component/*"
      goals="site"
      banner="Generating Site"
      ignoreFailures="true"/>

    <!--
     |
     | At this point because 'postProcessing' was turned on we have all
     | the processed POMs available to us in the ${reactorProjects} variable.
     |
     -->

    <j:forEach var="reactorProject" items="${reactorProjects}">

      ... Do whatever you want with the harvested information ...

    </j:forEach>
  </goal>
  
如果你需要聚合 N 个项目的文档,形成一个统一的视图,你可以参考  db.apache.org 站点,它从所有的子项目中收集   信息,最终形成一个有导航条,邮件列表,开发者列表和源码 repository 统一的站点。这解决   了在收集子项目信息过程中的冗余、易于产生错误的问题。 db.apache.org 的子项目只需关注   自身的信息,却可以自动的集成到高层的项目站点中。  

离线构建
如果你需要离线构建,你得在命令行中使用离线选项:  

maven -o jar:jar
        
这等同于:  

maven -Dmaven.mode.online=false jar:jar
        
或者你可以在属性文件中设置  maven.mode.online  属性为 false  

在联机模式下, maven 总是下载  SNAPSHOT  依赖包 请参考   使用 SNAPSHOT 依赖。如果本机 repository  上的当前版本比服务器上的还要新,你也许不想 maven 覆盖你的当前版本。如果不想下载,你可以   设置属性:  

maven.repo.remote.enabled=false
        
maven beta 9 版本中,这个属性并没有起作用 ( 新版本已经解决了这个问题 ) 。可以这样来清空  maven.repo.remote  属性:  

maven.repo.remote.enabled=
        
在命令行或属性文件中设置都一样。  

在下面的情形中,你需要同时设置 maven.repo.remote.enabled=false maven.mode.online=true :希望 javadoc 插件的 "-link" 选项起作用,而又不希望   下载任何 ( 包括 snapshot) 包。  

命令行选项介绍
如果你用命令行来构建,这里提供了一个关于命令行选项的快速参考。  

Options:
 -D,--define arg   
定义一个系统属性
 -E,--emacs        
输出简洁的日志信息
 -X,--debug        
输出 debug 信息
 -b,--nobanner     
禁止  logo banner
 -d,--dir arg      
设置指定的工作目录
 -e,--exception    
输出异常堆栈信息
 -f,--find arg     
通过搜寻项目文件来确定执行的项目文件及其工作目录
 -g,--goals        
显示可用的目标
 -h,--help         
显示帮助信息
 -i,--info         
显示系统信息
 -o,--offline      
离线构建
 -p,--pom arg      
指定项目文件
 -v,--version      
显示版本号
测试
测试资源
通常情况下,你需要在测试类路径上为测试指定某些资源。你可以在 POM 中使用  

下面的例子说明了如何递归的包含在 ${basedir}/src/test 目录中所有以 .xml .properties 为扩展名   的文件:  

<project>
  ...
  <build>
    ...
    <unitTest>
      ...
      <resources>
        <resource>
          <directory>${basedir}/src/test</directory>
          <includes>
            <include>**/*.xml</include>
            <include>**/*.properties</include>
          </includes>
        </resource>
      </resources>
    </unitTest>
  </build>
</project>
下面的例子说明了如何递归的包含在 ${basedir}/src/test 目录中所有以 .xml .properties 为扩展名   的文件,但 naughty.properties 文件除外。请注意增加的 project/build/unitTest/resources/excludes  节点:  

  <project>
    ...
    <build>
      ...
      <unitTest>
        ...
        <resources>
          <resource>
            <directory>${basedir}/src/test</directory>
            <includes>
              <include>**/*.xml</include>
              <include>**/*.properties</include>
            </includes>
            <excludes>
              <exclude>naughty.properties</exclude>
            </excludes>
          </resource>
        </resources>
      </unitTest>
    </build>
  </project>
运行一个单独的测试
下面的命令运行了一个单独的测试:  

maven -Dtestcase=org.foo.bar.MyTest test:single-test
打包
JAR 
资源

<project>
  ...
  <build>
    <resources>
      <!-- A -->
      <resource>
        <directory>${basedir}/src/conf</directory>
        <includes>
          <include>*.xml</include>
          <include>*.properties</include>
        </includes>
      </resource>
      <!-- B -->
      <resource>
        <directory>${basedir}/src/messages</directory>
        <targetPath>org/apache/maven/messages</targetPath>
        <includes>
          <include>messages*.properties</include>
        </includes>
      </resource>
    </resources>
  </build>
</project>
部署

固化 SNAPSHOT 依赖
在开发时使用 SNAPSHOT 依赖包非常方便,但是在部署的时候,你需要把所有的 SNAPSHOT 依赖包   固定下来,以便发布一个包含固定 jar 的版本。如果你发布了一个含 SNAPSHOT 依赖包的项目,而   这些 SNAPSHOT 在项目发布后发生了变更,你可能很快就会发现这个版本没法儿工作。  

SNAPSHOT 以时间戳为版本号部署到 Maven 上时, Maven 可以识别 foo-SNAPSHOT.jar 实际上相当   foo-20030101.010101.jar 。当部署的时刻来临,你可以用下面的命令,让 Maven SNAPSHOT  版本号变为时间戳版本号。  

maven convert-snapshots
Maven
会提供交互的方式让你选择哪个 SNAPSHOPT 依赖包应该固化下来。这一过程结束后, Maven  就会把刚才你的选择写会你的 POM  

如果你希望 Maven 简单的、尽可能最好的固化 SNAPSHOT 依赖包,你可以用下面的命令:  

maven convert-snapshots-auto
拷贝依赖 JAR
maven.xml 这样写下面的语句是最简单的拷贝依赖包的方法。  

<project
  xmlns:deploy="deploy">

  <goal name="deploy-my-project">
    ...
    <deploy:copy-deps todir="/path"/>
    ...
  </goal>

</project>
deploy:copy-deps 标签你就可以简单的把项目所有的依赖包拷贝到任何   目录,如果希望排除某个依赖包,需要给出一个依赖包的 id 列表,列表中依赖包就不会被拷贝。  

<project
  xmlns:deploy="deploy">

  <goal name="deploy-my-project">
    ...
    <deploy:copy-deps todir="/path" excludes="servletapi,commons-util"/>
    ...
  </goal>
</project>
命名约定
这部分将简要的描述项目对象模型 (POM) 中命名约定。本篇文档希望可以统一各式各样 jar 包命名   方法,这些 jar 包一般为 java 开发者社区广泛使用。  

规则和指南
项目
一个项目必须由一个唯一的的标识,标识由 a-z 小写字母和连线号构成,其首字母必须以小写字母   开头。  

<project>
  <groupId>bar</groupId>
  <artifactId>foo</artifactId>
  ...
</project>
所有项目间的引用都由组 id 和包 id 构成。到现在为止,在 POM 与此相关的是下面将要(上面提到的?)谈到的项目的   依赖声明。  

项目的名称应该易于阅读,可用于文档。  

<project>
  <groupId>bar</groupId>
  <artifactId>foo</artifactId>
  <name>The Grand Master Foo</name>
  ...
</project>
项目应该有一个组标识,组标识是名称的基础部分。  

<project>
  <groupId>bar</groupId>
  <artifactId>foo</artifactId>
  <name>The Grand Master Foo</name>
  ...
</project>
所有项目发布的包都应基于项目唯一的标识,并且放在基于项目的组 id 的目录中。对于上面的   项目来说,假定发布的包是 jar 类型的包,我们就会有如下目录结构:  

repository
 |
 +-- bar
     |-- distribution
     `-- jar
         |-- foo-1.0.jar
         `-- foo-2.0.jar
依赖
一个理想的典型依赖声明的例子可能会象这样:  

<project>
  <groupId>yourProject</groupId>
  <artifactId>yourArtifact</artifactId>
  <name>Your Groovey Machine</name>
  ...

  <dependencies>

   <dependency>
     <groupId>bar</groupId>
     <artifactId>foo</artifactId>
     <version>1.0</version>
   </dependency>

 </dependencies>

</project>
这样一来,依赖于 id foo1.0  版本的 bar 项目   属于 org.foo.bar 组。这个依赖会被解析为本地 repository jar 文件。上面   的情形假定发布的包是基于包 id 命名的。因此对于上述依赖, Maven 就会采用  foo-1.0.jar 作为 jar 名。  

就像用户反映的那样,这种理想的方式并不能适应所有的项目。有几种情形我们必须考虑调整   理想的依赖机制:  


发布的 jar 包的并未使用项目作为基础名,如 xercesImpl 就是所有发布的 jar 包的基础名   它与 gump id maven 中的 id 都不一样。  
发布的 jar 包没有使用任何版本声明,如许多 commons 组件并没有把版本号作为包名的一部分。  
有些项目即没有使用项目 id 作为基础名也没有版本声明。例如,最坏的情形是 Java Activation Framework  jar 包,它没有遵循其他 Sun 的命名规则,也没有在 jar 包中声明   版本号,甚至在 manifest 中都没有任何版本信息。  

在多数情形下,任何例外的情况都可以用  &lt;jar&gt;( 可选节点 ) 、或者是重命名来解决。   现在,许多 Jarkata 的产品在 repository 已经被重命名,因为在不久的未来,绝大多数的 Jarkarta   项目将用 maven 进行构建。但这不是公司政策,我们不需要解决所有情况的问题。  

发布多个包的项目
Maven
的依赖机制完全支持任何形式的多项目包。  Maven's dependency mechanism completely supports multiple project artifacts of any given type. 

下面的代码包含了 ant 的主 jar 包和 optional 包加上 hypothetical 包。  


<dependencies>

  <!-- A -->
  <dependency>
    <groupId>ant</groupId>
    <artifactId>ant</artifactId>
    <version>1.4.1</version>
  </dependency>

  <!-- B -->
  <dependency>
    <groupId>ant</groupId>
    <artifactId>ant-optional</artifactId>
    <version>1.4.1</version>
  </dependency>

  <!-- C -->
  <dependency>
    <groupId>ant</groupId>
    <artifactId>poorly-named</artifactId>
    <version>1.4.1</version>
  </dependency>

</dependencies>
所以 A), B)   C) 实际上是指向属于同一组的单个包的指针,这就是说,一个单独的依赖就是对某个组中的某个   包的引用。目前 artifact 如果没有特别说明的话,一般指的是 jar 包。但是依赖也可能是一个 war 文件或一个   发行包。我们试图在提供多数情况下 ( 构建大多需要 jar ) 使用的缺省方式的同时,也顾及灵活性。  

远程 Repository 布局
这部分文档将对 Maven 的远程 repositories 做一个概要的说明。目前,主 repository 位于  Ibiblio ,但是你也可以自己创建一   个远程 repositories ,其结果描述可以在这部分文档中找到。  

任何独立的项目在 repository 都有自己的目录。每个项目有一个唯一的项目 id 和同名目录,   项目的发行包就放在这个目录中。  

项目的目录中可以存放各种各样的 artifacts ,目前最为广泛使用的两种类型是 jar 包和发行包   下面是一个远程 repository 快照:  

repository
 |
 |-- ant
 |   |-- distribution
 |   `-- jars
 |       |-- ant-1.4.1.jar
 |       `-- ant-optional-1.4.1.jar
 +-- jsse
 |-- distribution
 `-- jars
     |-- jsse.jar
     |-- jcert.jar
     `-- jnet.jar
本地 Repository 布局
应该有一个接口集合的紧凑实现使本地 repository 目录结构更加随意一些。现在我只使用   了一个类来实现,显得有些臃肿。我还是认为本地和远程 repositories 应保持相同的结构   但是为了使用更乐于使用,我开始设计一些接口,用于满足用户自己安排自己本地 Repository  布局,相似的远程 Repositor 也在设计中。尽管目前本地 repository 仍与远程 repository  完全一致,我希望听到更多的用户反馈,以促进这些接口的开发,或者完全抛弃它。  

生成项目站点
Maven
可以为项目产生一个完成的 web 站点。这个 web 站点将包含各种各样、由许多 Maven 插件   产生的报告,如 javadocs ,代码度量,单元测试, changlog ,及其它 ...  本节文档接下来的   部分将阐述 Maven 支持的站点定制选项。  

颜色
考虑到一致性,缺省情况下,所有 Maven 产生的站点都使用相似的外观。这使用户一眼就能   认出由 Maven 产生的站点,产生熟悉的感觉,更加方便信息的获取。当然, Maven 开发组也   考虑到用户可能会希望定制他们的站点。修改 Maven 产生的站点,最简单的方法是指定你要   使用的颜色搭配。这只需要在 project.properties 简单的设置适当的属性   即可。下面是所有可用的属性描述在  xdoc plugin  

风格
如果你感觉颜色太过于简单,无法满足你的要求,你可以用自己的 stylesheet 。为了重载   ${basedir}/xdocs/stylesheets/ 中的 maven.css stylesheet ,你可以通过设置 maven.javadoc.stylesheet  属性来指定你的  javadoc 风格。  

报告
最后,如果你希望定制哪些报告需要自动产生,你需要在你的项目描述中包含  reports  标签库。   到目前为止,如果没有 reports 标签指定,所有插件报告都会产生。这个标签   允许你选择产生哪些报告而排斥另外一些报告,而且允许你安排顺序。  

目前的标准   报告集在 xdoc 中是硬编码实现的,它们是:  

maven-changelog-plugin
maven-changes-plugin
maven-checkstyle-plugin
maven-developer-activity-plugin
maven-file-activity-plugin
maven-javadoc-plugin
maven-jdepend-plugin
maven-junit-report-plugin
maven-jxr-plugin
maven-license-plugin
maven-linkcheck-plugin
maven-pmd-plugin
maven-tasklist-plugin
      
如果你希望产生缺省的报告,但是还想增加或删除一两个,最好的方法是:给  xdoc:register-reports 目标写一个前置目标 (postGoal)  

<postGoal name="xdoc:register-reports">
  <attainGoal name="maven-changelog-plugin:deregister"/>  
  <attainGoal name="maven-myown-plugin:register"/>  
</postGoal>
        
排除所有 Maven 产生的内容
某些情况下,用户需要构建只有文档的站点,或是构建聚合许多子项目的站点,但不希望   在站点上有个整体 项目文档 导航条。设置  maven.xdoc.includeProjectDocumentation 属性值为 no  即可解决这一问题。缺省的, Maven 会包含 项目文档 导航条,下面挂的是许多 Maven  生成的报告。  

Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=348197


[收藏到我的网摘]   qiquan36发表于 2005年04月15日 01:01:00

相关文章:
posted on 2006-12-07 11:29 芦苇 阅读(3262) 评论(0)  编辑  收藏 所属分类: IDE

只有注册用户登录后才能发表评论。


网站导航: