Maven最佳实践——目录的约定

Maven是服务于项目生命周期的,有些人说它是build工具,但build只是生命周期的一部分,它试图抽象整个项目生命周期,实际上它也做到了。几乎所有的项目都离不开Mave所定义的生命周期阶段(clean compile test package site...)。不止如此,基于这些阶段,Maven通过插件提供了绝大部分的默认实现,它们不用做任何配置或者仅需要很少的配置,就能帮你完成你的工作。

 

先看一个简单的基于Ant的build.xml文件。

<project name="my-project" default="dist" basedir=".">
    <description>
        simple example build file
    </description>
  <!-- set global properties for this build -->
  <property name="src" location="src/main/java"/>
  <property name="build" location="target/classes"/>
  <property name="dist"  location="target"/>

  <target name="init">
    <!-- Create the time stamp -->
    <tstamp/>
    <!-- Create the build directory structure used by compile -->
    <mkdir dir="${build}"/>
  </target>

  <target name="compile" depends="init"
        description="compile the source " >
    <!-- Compile the java code from ${src} into ${build} -->
    <javac srcdir="${src}" destdir="${build}"/>
  </target>

  <target name="dist" depends="compile"
        description="generate the distribution" >
    <!-- Create the distribution directory -->
    <mkdir dir="${dist}/lib"/>

    <!-- Put everything in ${build} into the MyProject-${DSTAMP}.jar file -->
    <jar jarfile="${dist}/lib/MyProject-${DSTAMP}.jar" basedir="${build}"/>
  </target>

  <target name="clean"
        description="clean up" >
    <!-- Delete the ${build} and ${dist} directory trees -->
    <delete dir="${build}"/>
    <delete dir="${dist}"/>
  </target>
</project>

 

这段代码做的事情是清除目录,创建目录,编译源文件,复制依赖至目标目录。这已经十分简单了,但是,为此你还是需要做一些配置:指定源码目录,指定编译字节码目录,指定目标目录,你还需要记住一些ant的配置命令,如delete, mkdir, javac, jar。这看起来没什么问题,至少目前是这样。

 

现在说说Ant或shell/bat存在的问题,首先,有很多配置需要你填写,源码目录,字节码目录……,每一个项目,你都要重复这些劳动;第二,也是更重要的一点,你根本无法保证N个项目的ant配置(或shell)配置使用了相同的风格,后果是,每接受一个项目,开发者都要去学习这份脚本,以了解如何构建项目。如果第一个原因只是为了技术的简化的话,第二个原因更是软件工程的因素,我们不是一个人在开发项目,不是只开发一个项目,所以应该时刻谨记为了别人,为了将来。

 

现在看看使用Maven我们需要什么配置,就一个pom.xml文件:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.sonatype.mavenbook</groupId>
  <artifactId>my-project</artifactId>
  <version>1.0</version>
</project>

 

不用惊讶,Maven不会变魔术,它能做到这么简单,是有条件的,条件就是你要遵守Maven约定。pom.xml所在的目录应为项目的根目录,假设该目录为${proj-dir},那么Maven有以下假设:

  • ${proj-dir}/src/main/java —— 存放项目的.java文件。
  • ${proj-dir}/src/main/resources —— 存放项目资源文件,如spring, hibernate配置文件。
  • ${proj-dir}/src/test/jave —— 存放所有测试.java文件,如JUnit测试类。
  • ${proj-dir}/src/test/resources —— 测试资源文件。
  • ${proj-dir}/target —— 项目输出位置。

运行一条mvn clean package命令,Maven会帮你清除target目录,重新建一个空的,编译src/main/java类至target/classes,复制src/main/resources的文件至target/classes,编译src/test/java至target/test-classes,复制src/test/resources的文件至target/test-classes;然后运行所有测试;测试通过后,使用jar命令打包,存储于target目录。Maven做的事情一点也不少,只是都对用户隐蔽起来了,它只要求你遵循它的约定。

 

这么做有什么好处呢?第一,显而易见,配置大量减少了,随着项目变得越复杂,这种优势就越明显。第二,我这里要强调的是,对于软件工程来说,所有使用Maven的项目,对外都暴露统一的命令集。如mvn clean install。只要项目被正确配置好了,任何一个新人,输入一行Maven命令,就能将项目构建起来了,这大大减少了交流学习的时间。

 

这时可能会有人说,我不想遵守这种约定呢?我要把源码放在${proj-dir}/src/code目录下。首先,问自己三遍,你真的需要这样做么?如果仅仅是因为喜好,那么别耍个性,个性意味着牺牲通用性,意味着增加无谓的复杂度。以下是一个“个性”的例子:

<project>
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.sonatype.mavenbook</groupId>
  <artifactId>my-project</artifactId>
  <version>1.0</version>
  <build>
    <sourceDirectory>src/java</sourceDirectory>
    <testSourceDirectory>src/test</testSourceDirectory>
    <outputDirectory>output/classes</outputDirectory>
    <testOutputDirectory>output/test-classes</testOutputDirectory>
    <directory>target/jar</directory>
  </build>
</project>

很显然,Maven允许你自定义,比如这个例子中,Maven就被配置成从src/java目录寻找源码,编译class文件至output/classes,从src/test寻找测试源码,编译至output/test-classes目录,最后,打包jar文件至target/jar目录。Maven允许你这么做,但不推荐你这么做。因为一旦你使用这种自定义,习惯Maven约定的人一开始会觉得奇怪,src/main/java目录去哪里了?target下面怎么没有我要的jar文件?这些都造成了无谓的交流成本提高。只有一些特殊的情况,这些自定义手段能帮你解决实际的问题,比如你在处理遗留代码,你没办法改变源码目录结构,这个时候只有让Maven妥协。

 

下面总结一些Maven的默认值,也就是说,虽然你没做什么配置,但是你应该知道Maven假设它们成立,也就是所谓的约定:



Maven约定

目录src/main/java
java源码目录
目录src/main/resources
资源文件目录
目录src/test/java
测试java源码目录
目录src/test/resources
测试资源文件目录
目录target
打包输出目录
目录target/classes
编译输出目录
目录target/test-classes
测试编译输出目录
目录target/site
项目site输出目录
目录src/main/webapp
web应用文件目录(当打包为war时),如WEB-INF/web.xml
jar
默认打包格式
*Test.java
Maven只会自动运行符合该命名规则的测试类
%user_home%/.m2
Maven默认的本地仓库目录位置
中央仓库
Maven默认使用远程中央仓库:http://repo1.maven.org/maven2
1.3
Maven Compiler插件默认以1.3编译,因此需要额外配置支持1.5

 

其实基本上所有的约定,或者说默认配置,都可以在Maven的超级POM(super pom)中找到。由于所有的POM都继承了这个超级POM(类似于java中所有类都继承于Object),因此它的默认配置就被继承了。以Maven 2.0.9为例,你可以在%m2_home%/lib/下看到一个名为maven-2.0.9-uber.jar的文件,打开这个文件,可以找到org/apache/maven/project/pom-4.0.0.xml这个文件,这就是超级POM。

 

Maven提供了一套科学的默认配置,它要求你遵循这些配置约定,然后它就会帮你处理日常的事务compile, test, package等等。使用Maven的时候,你应该尽可能遵循它的配置约定,一方面可以简化配置,另一方面可建立起一种标准,减少交流学习成本。一旦你习惯了这种约定,你得到的回报是巨大的。反之,恣意的做自定义,想要Maven像Ant一样听你的话,那么你会讨厌Maven,Maven也会讨厌你。

 

 

原帖地址:http://juvenshun.iteye.com/blog/293975

 

 

时间: 2024-09-18 03:53:28

Maven最佳实践——目录的约定的相关文章

《iOS网络编程与云端应用最佳实践》上线了-源码下载,样章-正式发售了

我的最新作品:<iOS网络编程与云端应用最佳实践>一书正式发售:(欢迎大家到京东.当当.亚马逊购买)    当当   亚马逊   京东 源码和试读章节和大家分享一下! <iOS网络编程与云端应用最佳实践>书籍源码下载地址(免费下载):   http://download.csdn.net/detail/tonny_guan/5419117 试读章节下载地址   http://download.csdn.net/detail/tonny_guan/5419123    可以通过微博在

Spring Data 数据库建模最佳实践

本文节选自电子书<Netkiller Architect 手札> 出处:http://www.netkiller.cn 作者:netkiller , QQ:13721218, 订阅号:netkiller-ebook 第 12 章 Spring Data 数据库建模最佳实践 目录 12.1. 分类表 12.2. 为字段增加索引 12.3. 复合索引 12.4. 一对多实例 12.5. ManyToMany 多对多 12.6. 外键级联删除 ORM的出现解决了程序猿学习数据库学历成本,也加快了开发

Maven实战. 2.7Maven安装最佳实践

2.7Maven安装最佳实践本节介绍一些在安装Maven过程中不是必须的,但十分有用的实践.2.7.1设置MAVEN_OPTS环境变量前面介绍Maven安装目录时我们了解到,运行mvn命令实际上是执行了Java命令,既然是运行Java,那么运行Java命令可用的参数当然也应该在运行mvn命令时可用.这个时候,MAVEN_OPTS环境变量就能派上用场.通常需要设置MAVEN_OPTS的值为-Xms128m -Xmx512m,因为Java默认的最大可用内存往往不能够满足Maven运行的需要,比如在项

PHP最佳实践

今天下午,我在读下面这篇文章. 虽然名字叫<PHP最佳实践>,但是它主要谈的不是编程规则,而是PHP应用程序的合理架构. 它提供了一种逻辑和数据分离的架构模式,属于MVC模式的一种实践.我觉得,这是很有参考价值的学习资料,类似的文章网上并不多,所以一边学习,一边就把它翻译了出来. 根据自己的理解,我总结了它的MVC模式的实现方式(详细解释见译文): * 视图层(View):前端网页: * 逻辑层(Controller):先是页逻辑(Page Controller),负责处理页面请求:然后,调用

【转载】Docker 镜像优化与最佳实践

阿里云高级研发工程师御坂在云栖TechDay41期的线下沙龙活动中分享了Docker镜像优化与最佳实践.本文为沙龙内容回顾. 从Docker镜像存储的原理开始,针对镜像的存储.网络传输,介绍如何在构建中对这些关键点进行优化.并介绍Docker最新的多阶段构建的功能,以解决构建依赖的中间产物问题. 镜像概念 镜像是什么? 从一个比较具体的角度去看,镜像就是一个多层存储的文件,相较于普通的ISO系统镜像来说,分层存储会带来两个优点: 一个是分层存储的镜像比较容易扩展,比如我们可以基于一个Ubuntu

Docker 镜像优化与最佳实践

云栖TechDay41期,阿里云高级研发工程师御坂带来Docker镜像优化与最佳实践.从Docker镜像存储的原理开始,针对镜像的存储.网络传输,介绍如何在构建中对这些关键点进行优化.并介绍Docker最新的多阶段构建的功能,以解决构建依赖的中间产物问题.   以下是精彩内容整理: 镜像概念 镜像是什么?从一个比较具体的角度去看,镜像就是一个多层存储的文件,相较于普通的ISO系统镜像来说,分层存储会带来两个优点,一个是分层存储的镜像比较容易扩展,比如我们可以基于一个Ubuntu镜像去构建我们的N

《配置管理最佳实践》——2.5 构建工具评估和选择

2.5 构建工具评估和选择 目前有很多好的构建工具,也有很多相关的最佳实践教程.这些教程可以指导你建立一个可靠.可扩展的构建流程.这里将会讨论一些工具和最佳实践,你可以有选择性地实施其中一些来支持公司的开发工作.目前软件开发中主要有几类比较流行的构建工具.不久以前,有段时间构建自动化仅仅意味着使用 Make(也许还有一些 shell 脚本)自动执行构建过程的每一个步骤.这种方法可以很好地支持 C 和 C++ 的构建.但是在实现的时候,要注意底层不同平台带来的差异性.我在 HP-UX, Solar

《配置管理最佳实践》——导读

** 前言 **配置管理(CM,Configuration Management)在任何开发工作中都起着非常关键的作用.我从事配置管理的实施和支持工作已经超过25年,本书中将讨论的大部分内容都直接来自于个人的经验.我实施并支持过各种配置管理的实践方法并达到这样一种状态--如果建立的过程或自动化没有按照预期般运作的话,我经常会在半夜里被惊醒.作为一名教师,我向超过九百多的专业技术人员传授过工业级的配置管理工具(同样,他们在成功地完成课程后都得到了我家的电话号码,这样如果我没有教授好知识和技能,即使

Android应用性能优化最佳实践.

移动开发 Android应用性能优化最佳实践 罗彧成 著 图书在版编目(CIP)数据 Android应用性能优化最佳实践 / 罗彧成著. -北京:机械工业出版社,2017.1 (移动开发) ISBN 978-7-111-55616-9 I. A- II. 罗- III. 移动终端-应用程序-程序设计 IV. TN929.53 中国版本图书馆CIP数据核字(2016)第315986号 Android应用性能优化最佳实践 出版发行:机械工业出版社(北京市西城区百万庄大街22号 邮政编码:100037