本书是国内第一本公开出版的Maven专著。它内容新颖,基于最新发布的Maven 30,不仅详尽讲解了Maven 30的所有新功能和新特性,而且还将这些新功能和新特性与Maven 2x版本进行了对比,以便于正在使用Maven 2x版本的用户能更好地理解。本书内容全面,以从专家的角度阐释Maven的价值开篇,全面介绍了Maven的安装、配置和基本使用方法,以便于初学者参考;详细讲解了坐标和依赖、Maven仓库、生命周期和插件、聚合与继承等Maven的核心概念,建议所有读者仔细阅读;系统性地阐述了使用Nexus建立私服、使用Maven进行测试、使用Hudson进行持续集成、使用Maven构建Web应用、Maven的版本管理、Maven的灵活构建、生成项目站点和Maven的m2eclipse插件等实用性较强的高级知识,读者可有选择性的阅读;扩展性地讲解了如何Maven和Archetype插件,这部分内容对需要编写插件扩展Maven或需要编写Archetype维护自己的项目骨架以更便于团队开发的读者来说尤为有帮助。它实战性强,不仅绝大部分知识点都有相应的案例,而且本书还在第4章设计了一个背景案例,后面的很多章节都是围绕这个案例展开的,可操作性极强。
本书适合所有Java程序员阅读,无论你是从未使用过Maven,亦或是已经使用Maven很长一段时间了,相信你都能从本书中获得有价值的参考。本书也适合所有项目经理阅读,它能帮助你更规范、更高效地管理Java项目。
本书法律顾问北京市展达律师事务所图书在版编目(CIP)数据Maven实战/许晓斌著.—北京: 机械工业出版社,2010.11书名原文: The Process of Software ArchitectingISBN 9787111321545Ⅰ.M…Ⅱ.许…Ⅲ.软件工具-程序设计Ⅳ.TP311.56中国版本图书馆CIP数据核字 (2010) 第196295号机械工业出版社(北京市西城区百万庄大街22号邮政编码100037)
2007年的时候,我加入了一个新成立的开发团队,我们一起做一个新的项目。经验较丰富的同事习惯性地开始编写Ant脚本,也有人希望能尝试一下Maven。当时我比较年轻,且富有激情,因此大家决定让我对Maven做些研究和实践。于是我慢慢开始学习并推广Maven,这期间有人支持,也有人抵触,而我则尽力地为大家排除困难,并做一些内部交流,渐渐地,抵触的人越来越少,我的工作也得到了大家的认可。
为什么一开始有人会抵触这一优秀的技术呢?后来我开始反思这一经历,我认为Maven陡峭的学习曲线和匮乏的文档是当时最主要的问题。为了能改善这个问题,我开始在博客中撰写各类关于Maven的中文博客,翻译了O’Reilly出版的《Maven权威指南》一书,并建立了国内的Maven中文社区,不定期地回答各类Maven相关问题,这在一定程度上推动了Maven这一优秀的技术在国内的传播。
后来我加入了Maven之父Jason Van Zyl创建的Sonatype,参与Nexus的开发并负责维护Maven中央仓库,这些工作使我对开源和Maven有了更深的认识,也给了我从头写一本关于Maven的书的信心。我希望它能够更贴近国内的技术人员的需求,能够出现在书店的某个角落里,给那些有心发现它的读者带来一丝欣喜。
该书写作后期适逢Maven 3的发布,这距离我刚接触Maven时已经过去3年有余,感叹时光的流逝!Maven在2007年至2010年取得了飞速的发展,现在几乎已经成为了所有Java开源项目的标配,Struts、Hibernate、 Ehcache等知名的开源项目都使用Maven进行管理。据了解,国内也有越来越多的知名的软件公司开始使用Maven管理他们的项目,例如阿里巴巴和淘宝。
首先,本书适合所有Java程序员阅读。由于自动化构建、依赖管理等问题并不只存在于Java世界,因此非Java程序员也能够从该书中获益。无论你是从未接触过Maven、还是已经用了Maven很长时间,亦或者想要扩展Maven,都能从本书获得有价值的参考建议。
第10~16章介绍了一些相对高级且离散的知识点,包括测试、持续集成与Hudson、Web项目与自动化部署、自动化版本管理、智能适应环境差异的灵活构建、站点生成,以及Maven的Eclipse插件m2eclipse,等等。读者可以根据自己实际需要和兴趣选择性地阅读。
第17~18章介绍了如何编写Archeype和Maven插件。一般的Maven用户在实际工作中往往不需要接触这些知识,如果你需要编写插件扩展Maven,或者需要编写Archetype维护自己的项目骨架以方便团队开发,那么可以仔细阅读这两章的内容。
大家可以从我的网站下载本书的代码:http://wwwjuvenxucom/mvninaction/,也可以通过我的网站与我取得联系,欢迎大家与我交流任何关于本书的问题和关于Maven的问题。
本书相当一部分的内容是在苏州十全街边的Solo咖啡馆完成的,老板Yin亲手烘焙咖啡豆、并能做出据说是苏州最好的咖啡,这小桥流水畔的温馨小屋能够帮我消除紧张和焦虑,和Yin有一句没一句的聊天也是相当的轻松。Yin还教会了我如何自己研磨咖啡豆、手冲滴率咖啡,让我能够每天在家里也能享受香气四溢的新鲜咖啡。
本书的书稿是使用Git和Unfuddle(http://unfuddlecom/)进行管理的,书中的大量截图是通过Jing(http://wwwtechsmithcom/jing/)制作的。
感谢二少、Garin、Sutra、JTux、红人、linux_china、Chris、Jdonee、zc0922、还有很多Maven中文社区的朋友,你们给了本书不少建议,并在我写作过程中不断鼓励我和支持我,你们是我写作最大的动力之一。
Maven实战第1章Maven简介11何为Maven
Maven这个词可以翻译为“知识的积累”,也可以翻译为“专家”或“内行”。本书将介绍Maven这一跨平台的项目管理工具。作为Apache组织中的一个颇为成功的开源项目,Maven主要服务于基于Java平台的项目构建、依赖管理和项目信息管理。无论是小型的开源类库项目,还是大型的企业级应用;无论是传统的瀑布式开发,还是流行的敏捷模式,Maven都能大显身手。
111何为构建
不管你是否意识到,构建(build)是每一位程序员每天都在做的工作。早上来到公司,我们做的第一件事情就是从源码库签出最新的源码,然后进行单元测试,如果发现失败的测试,会找相关的同事一起调试,修复错误代码。接着回到自己的工作上来,编写自己的单元测试及产品代码,我们会感激IDE随时报出的编译错误提示。
忙到午饭时间,代码编写得差不多了,测试也通过了,开心地享用午餐,然后休息。下午先在昏昏沉沉中开了个例会,会议结束后喝杯咖啡继续工作。刚才在会上经理要求看测试报告,于是找了相关工具集成进IDE,生成了像模像样的测试覆盖率报告,接着发了一封电子邮件给经理,松了口气。谁料QA小组又发过来了几个bug,没办法,先本地重现再说,于是熟练地用IDE生成了一个WAR包,部署到Web容器下,启动容器。看到熟悉的界面了,遵循bug报告,一步步重现了bug……快下班的时候,bug修好了,提交代码,通知QA小组,在愉快中结束了一天的工作。
仔细总结一下,我们会发现,除了编写源代码,我们每天有相当一部分时间花在了编译、运行单元测试、生成文档、打包和部署等烦琐且不起眼的工作上,这就是构建。如果我们现在还手工这样做,那成本也太高了,于是有人用软件的方法让这一系列工作完全自动化,使得软件的构建可以像全自动流水线一样,只需要一条简单的命令,所有烦琐的步骤都能够自动完成,很快就能得到最终结果。
112Maven是优秀的构建工具
前面介绍了Maven的用途之一是服务于构建,它是一个异常强大的构建工具,能够帮我们自动化构建过程,从清理、编译、测试到生成报告,再到打包和部署。我们不需要也不应该一遍又一遍地输入命令,一次又一次地点击鼠标,我们要做的是使用Maven配置好项目,然后输入简单的命令(如mvn clean install),Maven会帮我们处理那些烦琐的任务。
Maven是跨平台的,这意味着无论是在Windows上,还是在Linux或者Mac上,都可以使用同样的命令。
我们一直在不停地寻找避免重复的方法。设计的重复、编码的重复、文档的重复,当然还有构建的重复。Maven最大化地消除了构建的重复,抽象了构建生命周期,并且为绝大部分的构建任务提供了已实现的插件,我们不再需要定义过程,甚至不需要再去实现这些过程中的一些任务。最简单的例子是测试,我们没必要告诉Maven去测试,更不需要告诉Maven如何运行测试,只需要遵循Maven的约定编写好测试用例,当我们运行构建的时候,这些测试便会自动运行。
想象一下,Maven抽象了一个完整的构建生命周期模型,这个模型吸取了大量其他的构建脚本和构建工具的优点,总结了大量项目的实际需求。如果遵循这个模型,可以避免很多不必要的错误,可以直接使用大量成熟的Maven插件来完成我们的任务(很多时候我们可能都不知道自己在使用Maven插件)。此外,如果有非常特殊的需求,我们也可以轻松实现自己的插件。
Maven还有一个优点,它能帮助我们标准化构建过程。在Maven之前,十个项目可能有十种构建方式;有了Maven之后,所有项目的构建命令都是简单一致的,这极大地避免了不必要的学习成本,而且有利于促进项目团队的标准化。
综上所述,Maven作为一个构建工具,不仅能帮我们自动化构建,还能够抽象构建过程,提供构建任务实现;它跨平台,对外提供了一致的操作接口,这一切足以使它成为优秀的、流行的构建工具。
113Maven不仅仅是构建工具
Java不仅是一门编程语言,还是一个平台,通过JRuby和Jython,我们可以在Java平台上编写和运行Ruby和Python程序。我们也应该认识到,Maven不仅是构建工具,还是一个依赖管理工具和项目信息管理工具。它提供了中央仓库,能帮我们自动下载构件。
在这个开源的年代里,几乎任何Java应用都会借用一些第三方的开源类库,这些类库都可通过依赖的方式引入到项目中来。随着依赖的增多,版本不一致、版本冲突、依赖臃肿等问题都会接踵而来。手工解决这些问题是十分枯燥的,幸运的是Maven提供了一个优秀的解决方案,它通过一个坐标系统准确地定位每一个构件(artifact),也就是通过一组坐标Maven能够找到任何一个Java类库(如jar文件)。Maven给这个类库世界引入了经纬,让它们变得有秩序,于是我们可以借助它来有序地管理依赖,轻松地解决那些繁杂的依赖问题。
Maven还能帮助我们管理原本分散在项目中各个角落的项目信息,包括项目描述、开发者列表、版本控制系统地址、许可证、缺陷管理系统地址等。这些微小的变化看起来很琐碎,并不起眼,但却在不知不觉中为我们节省了大量寻找信息的时间。除了直接的项目信息,通过Maven自动生成的站点,以及一些已有的插件,我们还能够轻松获得项目文档、测试报告、静态分析报告、源码版本日志报告等非常具有价值的项目信息。
Maven还为全世界的Java开发者提供了一个免费的中央仓库,在其中几乎可以找到任何的流行开源类库。通过一些Maven的衍生工具(如Nexus),我们还能对其进行快速地搜索。只要定位了坐标,Maven就能够帮我们自动下载,省去了手工劳动。
使用Maven还能享受一个额外的好处,即Maven对于项目目录结构、测试用例命名方式等内容都有既定的规则,只要遵循了这些成熟的规则,用户在项目间切换的时候就免去了额外的学习成本,可以说是约定优于配置(Convention Over Configuration)。
12为什么需要Maven
Maven不是Java领域唯一的构建管理的解决方案。本节将通过一些简单的例子解释Maven的必要性,并介绍其他构建解决方案,如IDE、Make和Ant,并将它们与Maven进行比较。
121组装PC和品牌PC
笔者初中时开始接触计算机,到了高中时更是梦寐以求希望拥有一台自己的计算机。我的第一台计算机是赛扬733的,选购是一个漫长的过程,我先阅读了大量的杂志以了解各类配件的优劣,CPU、内存、主板、显卡,甚至声卡,我都仔细地挑选,后来还跑了很多商家,调货、讨价还价,组装好后自己装操作系统和驱动程序……虽然这花费了我大量时间,但我很享受这个过程。可是事实证明,装出来的机器稳定性不怎么好。
一年前我需要配一台工作站,这时候我已经没有太多时间去研究电脑配件了。我选择了某知名PC供应商的在线商店,大概浏览了一下主流的机型,选择了我需要的配置,然后下单、付款。接着PC供应商帮我组装电脑、安装操作系统和驱动程序。一周后,物流公司将电脑送到我的家里,我接上显示器、电源、鼠标和键盘就能直接使用了。这为我节省了大量时间,而且这台电脑十分稳定,商家在把电脑发送给我之前已经进行了很好的测试。对了,我还能享受两年的售后服务。
使用脚本建立高度自定义的构建系统就像买组装PC,耗时费力,结果也不一定很好。当然,你可以享受从无到有的乐趣,但恐怕实际项目中无法给你那么多时间。使用Maven就像购买品牌PC,省时省力,并能得到成熟的构建系统,还能得到来自于Maven社区的大量支持。唯一与购买品牌PC不同的是,Maven是开源的,你无须为此付费。如果有兴趣,你还能去了解Maven是如何工作的,而我们无法知道那些PC巨头的商业秘密。
122IDE不是万能的
当然,我们无法否认优秀的IDE能大大提高开发效率。当前主流的IDE如Eclipse和NetBeans等都提供了强大的文本编辑、调试甚至重构功能。虽然使用简单的文本编辑器和命令行也能完成绝大部分开发工作,但很少有人愿意那样做。然而,IDE是有其天生缺陷的:
IDE依赖大量的手工操作。编译、测试、代码生成等工作都是相互独立的,很难一键完成所有工作。手工劳动往往意味着低效,意味着容易出错。
很难在项目中统一所有的IDE配置,每个人都有自己的喜好。也正是由于这个原因,一个在机器A上可以成功运行的任务,到了机器B的IDE中可能就会失败。
我们应该合理利用IDE,而不是过多地依赖它。对于构建这样的任务,在IDE中一次次地点击鼠标是愚蠢的行为。Maven是这方面的专家,而且主流IDE都集成了Maven,我们可以在IDE中方便地运行Maven执行构建。
123Make
Make也许是最早的构建工具,它由Stuart Feldman于1977年在Bell实验室创建。Stuart Feldman也因此于2003年获得了ACM国际计算机组织颁发的软件系统奖。目前Make有很多衍生实现,包括最流行的GNU Make和BSD Make,还有Windows平台的Microsoft nmake等。
Make由一个名为Makefile的脚本文件驱动,该文件使用Make自己定义的语法格式。其基本组成部分为一系列规则(Rules),而每一条规则又包括目标(Target)、依赖(Prerequisite)和命令(Command)。Makefile的基本结构如下:
TARGET… : PREREQUISITE…
COMMAND
…
…
Make通过一系列目标和依赖将整个构建过程串联起来,同时利用本地命令完成每个目标的实际行为。Make的强大之处在于它可以利用所有系统的本地命令,尤其是UNIX/Linux系统,丰富的功能、强大的命令能够帮助Make快速高效地完成任务。
但是,Make将自己和操作系统绑定在一起了。也就是说,使用Make,就不能实现(至少很难)跨平台的构建,这对于Java来说是非常不友好的。此外,Makefile的语法也成问题,很多人抱怨Make构建失败的原因往往是一个难以发现的空格或Tab使用错误。
124Ant
Ant不是指蚂蚁,而是意指“另一个整洁的工具”(Another Neat Tool),它最早用来构建著名的Tomcat,其作者James Duncan Davidson创作它的动机就是因为受不了Makefile的语法格式。我们可以将Ant看成是一个Java版本的Make,也正因为使用了Java,Ant是跨平台的。此外,Ant使用XML定义构建脚本,相对于Makefile来说,这也更加友好。
与Make类似,Ant有一个构建脚本buildxml,如下所示:
buildxml的基本结构也是目标(target)、依赖(depends),以及实现目标的任务。比如在上面的脚本中,jar目标用来创建应用程序jar文件,该目标依赖于compile目标,后者执行的任务是创建一个名为classes的文件夹,编译当前目录的java文件至classes目录。compile目标完成后,jar目标再执行自己的任务。Ant有大量内置的用Java实现的任务,这保证了其跨平台的特质,同时,Ant也有特殊的任务exec来执行本地命令。
和Make一样,Ant也都是过程式的,开发者显式地指定每一个目标,以及完成该目标所需要执行的任务。针对每一个项目,开发者都需要重新编写这一过程,这里其实隐含着很大的重复。Maven是声明式的,项目构建过程和过程各个阶段所需的工作都由插件实现,并且大部分插件都是现成的,开发者只需要声明项目的基本元素,Maven就执行内置的、完整的构建过程。这在很大程度上消除了重复。
Ant是没有依赖管理的,所以很长一段时间Ant用户都不得不手工管理依赖,这是一个令人头疼的问题。幸运的是,Ant用户现在可以借助Ivy管理依赖。而对于Maven用户来说,依赖管理是理所当然的,Maven不仅内置了依赖管理,更有一个可能拥有全世界最多Java开源软件包的中央仓库,Maven用户无须进行任何配置就可以直接享用。
该小节内容整理自网友Arthas最早在Maven中文MSN群中的讨论,在此表示感谢125不重复发明轮子
小张是一家小型民营软件公司的程序员,他所在的公司要开发一个新的Web项目。经过协商,决定使用Spring、iBatis和Tapstry。jar包去哪里找呢?公司里估计没有人能把Spring、iBatis和Tapstry所使用的jar包一个不少地找出来。大家的做法是,先到Spring的站点上去找一个springwithdependencies,然后去iBatis的网站上把所有列出来的jar包下载下来,对Tapstry、Apache commons等执行同样的操作。项目还没有开始,WEBINF/lib下已经有近百个jar包了,带版本号的、不带版本号的、有用的、没用的、相冲突的,怎一个“乱”字了得!
在项目开发过程中,小张不时地发现版本错误和版本冲突问题,他只能硬着头皮逐一解决。项目开发到一半,经理发现最终部署的应用的体积实在太大了,要求小张去掉一些没用的jar包,于是小张只能加班加点地一个个删……
小张隐隐地觉得这些依赖需要一个框架或者系统来进行管理。
小张喜欢学习流行的技术,前几年Ant十分流行,他学了,并成为了公司这方面的专家。小张知道,Ant打包,无非就是创建目录,复制文件,编译源代码,使用一堆任务,如copydir、fileset、classpath、ref、target,然后再jar、zip、war,打包就成功了。
项目经理发话了:“兄弟们,新项目来了,小张,你来写Ant脚本!”
“是,保证完成任务!”接着,小张继续创建一个新的XML文件。target clean; target compile; target jar; …… 不知道他是否想过,在他写的这么多的Ant脚本中,有多少是重复劳动,有多少代码会在一个又一个项目中重现。既然都差不多,有些甚至完全相同,为什么每次都要重新编写?
终于有一天,小张意识到了这个问题,想复用Ant脚本,于是在开会时他说:“以后就都用我这个规范的Ant脚本吧,新的项目只要遵循我定义的目录结构就可以了。”经理听后觉得很有道理:“嗯,确实是个进步。”
这时新来的研究生发言了:“经理,用Maven吧,这个在开源社区很流行,比Ant更方便。”小张一听很惊讶,Maven真比自己的“规范化Ant”强大?其实他不知道自己只是在重新发明轮子,Maven已经有一大把现成的插件,全世界都在用,你自己不用写任何代码!
为什么没有人说“我自己写的代码最灵活,所以我不用Spring,我自己实现IoC;我不用Hibernate,我自己封装JDBC”?
13Maven与极限编程
极限编程(XP)是近些年在软件行业红得发紫的敏捷开发方法,它强调拥抱变化。该软件开发方法的创始人Kent Beck提出了XP所追求的价值、实施原则和推荐实践。下面看一下Maven是如何适应XP的。
首先看一下Maven如何帮助XP团队实现一些核心价值:
简单。Maven暴露了一组一致、简洁的操作接口,能帮助团队成员从原来的高度自定义的、复杂的构建系统中解脱出来,使用Maven现有的成熟的、稳定的组件也能简化构建系统的复杂度。
交流与反馈。与版本控制系统结合后,所有人都能执行最新的构建并快速得到反馈。此外,自动生成的项目报告也能帮助成员了解项目的状态,促进团队的交流。
此外,Maven更能无缝地支持或者融入到一些主要的XP实践中:
测试驱动开发(TDD)。TDD强调测试先行,所有产品都应该由测试用例覆盖。而测试是Maven生命周期的最重要的组成部分之一,并且Maven有现成的成熟插件支持业界流行的测试框架,如JUnit和TestNG。
十分钟构建。十分钟构建强调我们能够随时快速地从源码构建出最终的产品。这正是Maven所擅长的,只需要一些配置,之后用一条简单的命令就能让Maven帮你清理、编译、测试、打包、部署,然后得到最终的产品。
持续集成(CI)。CI强调项目以很短的周期(如15分钟)集成最新的代码。实际上,CI的前提是源码管理系统和构建系统。目前业界流行的CI服务器如Hudson和CruiseControl都能很好地和Maven进行集成。也就是说,使用Maven后,持续集成会变得更加方便。
富有信息的工作区。 这条实践强调开发者能够快速方便地了解到项目的最新状态。当然,Maven并不会帮你把测试覆盖率报告贴到墙上,也不会在你的工作台上放个鸭子告诉你构建失败了。不过使用Maven发布的项目报告站点,并配置你需要的项目报告,如测试覆盖率报告,都能帮你把信息推送到开发者眼前。
上述这些实践并非只在XP中适用。事实上,除了其他敏捷开发方法如SCRUM之外,几乎任何软件开发方法都能借鉴这些实践。也就是说,Maven几乎能够很好地支持任何软件开发方法。
例如,在传统的瀑布模型开发中,项目依次要经历需求开发、分析、设计、编码、测试和集成发布阶段。从设计和编码阶段开始,就可以使用Maven来建立项目的构建系统。在设计阶段,也完全可以针对设计开发测试用例,然后再编写代码来满足这些测试用例。然而,有了自动化构建系统,我们可以节省很多手动的测试时间。此外,尽早地使用构建系统集成团队的代码,对项目也是百利而无一害。最后,Maven还能帮助我们快速地发布项目。
14被误解的Maven
C++之父Bjarne Stroustrup说过一句话:“只有两类计算机语言,一类语言天天被人骂,还有一类没人用。”当然这话也不全对,大红大紫的Ruby不仅有人用,而且骂的人也少。用户最多的Java得到的骂声就不绝于耳了。Maven的用户也不少,它的邮件列表目前在Apache项目中排名第4(http://wwwnabblecom/Apachef 90html)。
让我们看看Maven受到了哪些质疑,笔者将对这些质疑逐一解释。
“Maven对于IDE(如Eclipse和IDEA)的支持较差,bug多,而且不稳定。”
相对于JUnit和Ant来说,Maven比较年轻,IDE集成等衍生产品还不够全面和成熟。但是,我们一定要知道,使用Maven最高效的方式永远是命令行,IDE在自动化构建方面有天生的缺陷。此外,Eclipse的Maven插件——m2eclipse是一个比较优秀和成熟的工具,NetBeans也在积极地为更好地集成Maven而努力,自IntelliJ IDEA开源后,也有望看到其对Maven更好的集成。
“Maven采用了一个糟糕的插件系统来执行构建,新的、破损的插件会让你的构建莫名其妙地失败。”
自Maven 209开始,所有核心的插件都设定了稳定版本,这意味着日常使用Maven时几乎不会受到不稳定插件的影响。此外,Maven社区也提倡为你使用的任何插件设定稳定的版本。如果我们有好的实践不采纳,遇到了问题就抱怨,未免不够公允。从Maven 3开始,如果你使用插件时未设定版本,会看到警告信息。
“Maven过于复杂,它就是构建系统的EJB 2。”
不要指望Maven十分简单,这几乎是不可能的。Maven是用来管理项目的,清理、编译、测试、打包、发布,以及一些自定义的过程本身就是一件复杂的事情。目前在Java社区还有比Maven更强大、更简单的构建工具吗?答案是否定的。我们可以尝试去帮助Maven让它变得更简单,而不是抛弃它,然后自己实现一套更加复杂的构建系统。
“Maven的仓库十分混乱,当无法从仓库中得到需要的类库时,我需要手工下载复制到本地仓库中。”
Maven的中央仓库确实不完美,你也许会发现某个jar包出现在两个不同的路径下。这不是Maven的错,这是开源项目本身改变了自身的坐标。如果没有中央仓库,你将不得不去开源项目首页寻找下载链接,这不是更费事吗?现在有很多的Maven仓库搜索服务。无法从中央仓库找到你需要的类库?由于许可证等因素,这是完全有可能的,这时你需要做的是建立一个组织内部的仓库服务器,你会发现这会给你带来许多意想不到的好处。
“缺乏文档是理解和使用Maven的一个主要障碍!”
这是事实。Maven官方站点的文档十分凌乱,各种插件的文档更是需要费力寻找。Sonatype编写的《Maven权威指南》很好地改善了这一状况,但由于该书的某些部分与国内的现状有些脱离,且翻译速度无法跟上原版的更新速度,于是笔者编写本书,目的也是帮助大家理解和使用Maven。
15小结
本章只是从概念上简单地介绍了一下Maven,通过本章我们应该能大致了解Maven是什么,以及它有什么用途。我们还将Maven与其他流行的构建工具(如Make和Ant)做了一些比较和分析。如果你没用过Maven,但有Make或者Ant的使用经验,相信通过比较你能更清楚地了解各种工具的优劣,并且会对Maven有一个理性的认识。
将Maven和极限编程结合起来分析是为了让大家从另一个角度了解Maven,毕竟软件开发离不开对于软件过程的理解。
本章最后还收集了一些用户对Maven的误解,并逐条进行了分析和解释,希望能够消除大家的误解,从而积极地接受Maven,最终从Maven中受益。
Maven实战第2章Maven的安装和配置第1章介绍了Maven是什么,以及为什么要使用Maven,我们将从本章开始实际接触Maven。本章首先将介绍如何在主流的操作系统下安装Maven,并详细解释Maven的安装文件;其次还会介绍如何在主流的IDE中集成Maven,以及Maven安装的最佳实践。
21在Windows上安装Maven
211检查JDK安装
在安装Maven之前,首先要确认你已经正确安装了JDK。Maven可以运行在JDK 14及以上的版本上。本书的所有样例都基于JDK 5及以上版本。打开Windows的命令行,运行如下的命令来检查Java安装: C:\Users\Juven Xu>echo %JAVA_HOME%
C:\Users\Juven Xu>javaversion结果如图2-1所示: 图2-1Windows中检查Java安装
上述命令首先检查环境变量JAVA_HOME是否指向了正确的JDK目录,接着尝试运行java命令。如果Windows无法执行java命令,或者无法找到JAVA_HOME环境变量,就需要检查Java是否安装了,或者环境变量是否设置正确。关于环境变量的设置,请参考213节。
212下载Maven
请访问Maven的下载页面:http://mavenapacheorg/downloadhtml,其中包含针对不同平台的各种版本的Maven下载文件。对于首次接触Maven的读者来说,推荐使用Maven 30,因此需要下载apachemaven30binzip。当然,如果你对Maven的源代码感兴趣并想自己构建Maven,还可以下载apachemaven30srczip。该下载页面还提供了md5校验和(checksum)文件和asc数字签名文件,可以用来检验Maven分发包的正确性和安全性。
在编写本书的时候,Maven 2的最新版本是221,Maven 3基本完全兼容Maven 2,而且比Maven 2的性能更好,还对其中某些功能进行了改进。如果你之前一直使用Maven 2,现在正犹豫是否要升级,那就大可不必担心了,快点尝试一下Maven 3吧!
213本地安装
将安装文件解压到指定的目录中,如:D:\bin>jar xvf "C:\Users\Juven Xu\Downloads\apachemaven30 binzip"这里的Maven安装目录是D:\bin\apachemaven30,接着需要设置环境变量,将Maven安装配置到操作系统环境中。
打开系统属性面板(在桌面上右击“我的电脑”→“属性”),单击高级系统设置,再单击环境变量,在系统变量中新建一个变量,变量名为M2_HOME,变量值为Maven的安装目录D:\bin\apachemaven30。单击“确定”按钮,接着在系统变量中找到一个名为Path的变量,在变量值的末尾加上%M2_HOME%\bin;。注意:多个值之间需要有分号隔开,然后单击“确定”按钮。至此,环境变量设置完成。详细情况如图2-2所示。图2-2Windows中系统环境变量配置
值得注意的是Path环境变量。当我们在cmd中输入命令时,Windows首先会在当前目录中寻找可执行文件或脚本,如果没有找到,Windows会接着遍历环境变量Path中定义的路径。由于将%M2_HOME%\bin添加到了Path中,而这里%M2_HOME%实际上是引用了前面定义的另一个变量,其值是Maven的安装目录。因此,Windows会在执行命令时搜索目录D:\bin\apachemaven30\bin,而mvn执行脚本的位置就是这里。
了解环境变量的作用之后,现在打开一个新的cmd窗口(这里强调新的窗口是因为新的环境变量配置需要新的cmd窗口才能生效),运行如下命令检查Maven的安装情况:C:\Users\Juven Xu>echo %M2_HOME%
C:\Users\Juven Xu>mvnv 运行结果如图2-3所示。图2-3Windows中检查Maven安装
第一条命令echo %M2_HOME%用来检查环境变量M2_HOME是否指向了正确的Maven安装目录;而mvnv执行了第一条Maven命令,以检查Windows是否能够找到正确的mvn执行脚本。
214升级Maven
Maven更新比较频繁,因此用户往往会需要更新Maven安装以获得更多、更酷的新特性,并避免一些旧的bug。
在Windows上更新Maven非常简便,只需要下载新的Maven安装文件,解压至本地目录,然后更新M2_HOME环境变量即可。例如,假设Maven推出了新版本31,我们将其下载然后解压至目录D:\bin\apachemaven31,接着遵照前一节描述的步骤编辑环境变量M2_HOME,更改其值为D:\bin\apachemaven31。至此,更新就完成了。同理,如果需要使用某一个旧版本的Maven,也只需要编辑M2_HOME环境变量指向旧版本的安装目录。
22在基于UNIX的系统上安装Maven
Maven是跨平台的,它可以在任何一种主流的操作系统上运行。本节将介绍如何在基于UNIX的系统(包括Linux、Mac OS以及FreeBSD等)上安装Maven。
221下载和安装
首先,与在Windows上安装Maven一样,需要检查JAVA_HOME环境变量以及Java命令,这里对细节不再赘述。命令如下:juven@juvenubuntu:~$ echo $JAVA_HOME
juven@juvenubuntu:~$ javaversion运行结果如图2-4所示。 图2-4Linux中检查Java安装
接着到http://mavenapacheorg/downloadhtml下载Maven安装文件,如apachemaven30bintargz,然后解压到本地目录: juven@juvenubuntu:bin$ tarxvzf apachemaven30bintargz 现在已经创建好了一个Maven安装目录apachemaven30。虽然直接使用该目录配置环境变量之后就能使用Maven了,但这里的推荐做法是,在安装目录旁平行地创建一个符号链接,以方便日后的升级: juven@juvenubuntu:bin$ lns apachemaven30 apachemaven
juven@juvenubuntu:bin$ lsl
total 4
lrwxrwxrwx 1 juven juven18 20090920 15:43 apachemaven -> apachemaven30
drwxrxrx 6 juven juven 4096 20090920 15:39 apachemaven30接下来,需要设置M2_HOME环境变量指向符号链接apachemaven,并且把Maven安装目录下的bin/文件夹添加到系统环境变量PATH中: juven@juvenubuntu:bin$ export M2_HOME=/home/juven/bin/apachemaven
juven@juvenubuntu:bin$ export PATH=$PATH:$M2_HOME/bin一般来说,需要将这两行命令加入到系统的登录shell脚本中去,以Ubuntu 810为例,编辑~/bashrc文件,添加这两行命令。这样,每次启动一个终端,这些配置就能自动执行。
至此,安装完成。可以运行以下命令检查Maven安装:juven@juvenubuntu:bin$ echo $M2_HOME
juven@juvenubuntu:bin$ mvnv运行结果如图2-5所示。图2-5Linux中检查Maven安装
222升级Maven
在基于UNIX的系统上,可以利用符号链接这一工具来简化Maven的升级,不必像在Windows上那样,每次升级都必须更新环境变量。
前一小节中我们提到,解压Maven安装包到本地之后,平行地创建一个符号链接,然后在配置环境变量时引用该符号链接,这样做是为了方便升级。现在,假设需要升级到新的Maven 31版本,将安装包解压到与前一版本平行的目录下,然后更新符号链接指向31版的目录便可: juven@juvenubuntu:bin$ rm apachemaven
juven@juvenubuntu:bin$ lns apachemaven31/apachemaven
juven@juvenubuntu:bin$ lsl
total 8
lrwxrwxrwx1 juven juven17 2009-09-20 16:13 apachemaven -> apachemaven31/
drwxrxrx 6 juven juven 4096 2009-09-20 15:39 apachemaven30
drwxrxrx 2 juven juven 4096 2009-09-20 16:09 apachemaven31同理,可以很方便地切换到Maven的任意一个版本。现在升级完成了,可以运行mvnv进行检查。
23安装目录分析
前面讲述了如何在各种操作系统中安装和升级Maven。现在来仔细分析一下Maven的安装文件。
231M2_HOME
前面讲到设置M2_HOME环境变量指向Maven的安装目录,本书之后所有使用M2_HOME的地方都指代了该安装目录。下面看一下该目录的结构和内容: bin
boot
conf
lib
LICENSEtxt
NOTICEtxt
READMEtxt bin: 该目录包含了mvn运行的脚本,这些脚本用来配置Java命令,准备好classpath和相关的Java系统属性,然后执行Java命令。其中mvn是基于UNIX平台的shell脚本,mvnbat是基于Windows平台的bat脚本。在命令行输入任何一条mvn命令时,实际上就是在调用这些脚本。该目录还包含了mvnDebug和mvnDebugbat两个文件,同样,前者是UNIX平台的shell脚本,后者是Windows平台的bat脚本。那么mvn和mvnDebug有什么区别和关系呢?打开文件我们就可以看到,两者基本是一样的,只是mvnDebug多了一条MAVEN_DEBUG_OPTS配置,其作用就是在运行Maven时开启debug,以便调试Maven本身。此外,该目录还包含m2conf文件,这是classworlds的配置文件,后面会介绍classworlds。
boot: 该目录只包含一个文件,以maven 30为例,该文件为plexusclassworlds223jar。plexusclassworlds是一个类加载器框架,相对于默认的java类加载器,它提供了更丰富的语法以方便配置,Maven使用该框架加载自己的类库。更多关于classworlds的信息请参考http://classworldscodehausorg/。对于一般的Maven用户来说,不必关心该文件。
conf: 该目录包含了一个非常重要的文件settingsxml。直接修改该文件,就能在机器上全局地定制Maven的行为。一般情况下,我们更偏向于复制该文件至~/m2/目录下(~表示用户目录),然后修改该文件,在用户范围定制Maven的行为。后面将会多次提到settingsxml,并逐步分析其中的各个元素。
lib: 该目录包含了所有Maven运行时需要的Java类库,Maven本身是分模块开发的,因此用户能看到诸如mavencore30jar、mavenmodel30jar之类的文件。此外,这里还包含一些Maven用到的第三方依赖,如commoncli12jar、googlecollection10jar等。对于Maven 2来说,该目录只包含一个如maven221uberjar的文件,原本各为独立JAR文件的Maven模块和第三方类库都被拆解后重新合并到了这个JAR文件中。可以说,lib目录就是真正的Maven。关于该文件,还有一点值得一提的是,用户可以在这个目录中找到Maven内置的超级POM,这一点在85节详细解释。其他: LICENSEtxt记录了Maven使用的软件许可证Apache License Version 20; NOTICEtxt记录了Maven包含的第三方软件;而READMEtxt则包含了Maven的简要介绍,包括安装需求及如何安装的简要指令等。
232~/m2
在讲述该小节之前,我们先运行一条简单的命令:mvn help:system。该命令会打印出所有的Java系统属性和环境变量,这些信息对我们日常的编程工作很有帮助。这里暂不解释help:system涉及的语法,运行这条命令的目的是让Maven执行一个真正的任务。我们可以从命令行输出看到Maven会下载mavenhelpplugin,包括pom文件和jar文件。这些文件都被下载到了Maven本地仓库中。
现在打开用户目录,比如当前的用户目录是C:\Users\Juven Xu\,你可以在Vista和Windows7中找到类似的用户目录。如果是更早版本的Windows,该目录应该类似于C:\Document and Settings\Juven Xu\。在基于UNIX的系统上,直接输入cd 回车,就可以转到用户目录。为了方便,本书统一使用符号 ~ 指代用户目录。
在用户目录下可以发现m2文件夹。默认情况下,该文件夹下放置了Maven本地仓库m2/repository。所有的Maven构件都被存储到该仓库中,以方便重用。可以到~/m2/repository/org/apache/maven/plugins/mavenhelpplugins/目录下找到刚才下载的mavenhelpplugin的pom文件和jar文件。Maven根据一套规则来确定任何一个构件在仓库中的位置,这一点在第6章将会详细阐述。由于Maven仓库是通过简单文件系统透明地展示给Maven用户的,有些时候可以绕过Maven直接查看或修改仓库文件,在遇到疑难问题时,这往往十分有用。
默认情况下,~/m2目录下除了repository仓库之外就没有其他目录和文件了,不过大多数Maven用户需要复制M2_HOME/conf/settingsxml文件到~/m2/settingsxml。这是一条最佳实践,我们将在27小节详细解释。
24设置HTTP代理
有时候你所在的公司基于安全因素考虑,要求你使用通过安全认证的代理访问因特网。这种情况下,就需要为Maven配置HTTP代理,才能让它正常访问外部仓库,以下载所需要的资源。
首先确认自己无法直接访问公共的Maven中央仓库,直接运行命令ping repo1mavenorg可以检查网络。如果真的需要代理,先检查一下代理服务器是否畅通。比如现在有一个IP地址为21814227197,端口为3128的代理服务,我们可以运行telnet 21814227197 3128来检测该地址的该端口是否畅通。如果得到出错信息,需要先获取正确的代理服务信息;如果telnet连接正确,则输入ctrl+],然后q,回车,退出即可。
检查完毕之后,编辑~/m2/settingsxml文件(如果没有该文件,则复制$M2_HOME/conf/settingsxml)。添加代理配置如下:
…
myproxy
21814227197
…
这段配置十分简单,proxies下可以有多个proxy元素,如果声明了多个proxy元素,则默认情况下第一个被激活的proxy会生效。这里声明了一个id为myproxy的代理,active的值为true表示激活该代理,protocol表示使用的代理协议,这里是http。当然,最重要的是指定正确的主机名(host元素)和端口(port元素)。上述XML配置中注释掉了username、password、nonProxyHost几个元素。当代理服务需要认证时,就需要配置username和password。nonProxyHost元素用来指定哪些主机名不需要代理,可以使用“|”符号来分隔多个主机名。此外,该配置也支持通配符,如*googlecom表示所有以googlecom结尾的域名访问都不要通过代理。
25安装m2eclipse
Eclipse是一款非常优秀的IDE。除了基本的语法标亮、代码补齐、XML编辑等基本功能外,最新版的Eclipse还能很好地支持重构,并且集成了JUnit、CVS、Mylyn等各种流行工具。可惜Eclipse默认没有集成对Maven的支持。幸运的是,由Maven之父Jason Van Zyl创立的Sonatype公司建立了m2eclipse项目。这是Eclipse下的一款十分强大的Maven插件,可以访问http://m2eclipsesonatypeorg/了解更多该项目的信息。
本小节将介绍如何安装m2eclipse插件,后续的章节会逐步介绍m2eclipse插件的使用。
现在以Eclipse 36为例逐步讲解m2eclipse的安装。启动Eclipse之后,在菜单栏中选择Help,然后选择Install New Software,接着你会看到一个Install对话框。单击Work with:字段边上的Add按钮,会弹出一个新的Add Repository对话框。在Name字段中输入m2e,在Location字段中输入http://m2eclipsesonatypeorg/sites/m2e,然后单击OK按钮。Eclipse会下载m2eclipse安装站点上的资源信息。等待资源载入完成之后,再将其全部展开,就能看到图2-6所示的界面。 图2-6m2eclipse的核心安装资源列表
图2-6显示了m2eclipse的核心模块Maven Integration for Eclipse (Required),选择后单击Next按钮,Eclipse会自动计算模块间依赖,然后给出一个将被安装的模块列表。确认无误后,继续单击Next按钮,这时会看到许可证信息。m2eclipse使用的开源许可证是Eclipse Public License v10,选择I accept the terms of the license agreements,然后单击Finish按钮,接着就耐心等待Eclipse下载安装这些模块,如图2-7所示。图2-7m2eclipse安装进度
除了核心组件之外,m2eclipse还提供了一组额外组件,主要是为了方便与其他工具如Subversion进行集成,这些组件的安装地址为http://m2eclipsesonatypeorg/sites/m2eextras。使用前面类似的安装方法,可以看到图2-8所示的组件列表。
下面简单解释一下这些组件的用途。
1 重要的
Maven SCM handler for Subclipse (Optional):Subversion是非常流行的版本管理工具。该模块能够帮助我们直接从Subversion服务器签出Maven项目,不过前提是需要首先安装Subclipse(http://subclipsetigrisorg/)。
Maven SCM Integration (Optional):Eclipse环境中Maven与SCM集成核心的模块。它利用各种SCM工具如SVN实现Maven项目的签出和具体化等操作。
2 不重要的
Maven issue tracking configurator for Mylyn 3x (Optional):该模块能够帮助我们使用POM中的缺陷跟踪系统信息连接Mylyn至服务器。
Maven SCM handler for Team/CVS (Optional):该模块帮助我们从CVS服务器签出Maven项目,如果还在使用CVS,就需要安装它。
Maven Integration for WTP (Optional):使用该模块可以让Eclipse自动读取POM信息并配置WTP项目。
M2Eclipse Extensions Development Support (Optional):用来支持扩展m2eclipse,一般用户不会用到。
图2-8m2eclipse的额外组件安装资源列表
Project configurators for commonly used maven plugins (temporary):一个临时的组件,用来支持一些Maven插件与Eclipse的集成,建议安装。
读者可以根据自己的需要安装相应组件,具体步骤这里不再赘述。
待安装完毕后,重启Eclipse。现在来验证一下m2eclipse是否正确安装了。首先,单击菜单栏中的Help,然后选择About Eclipse。在弹出的对话框中,单击Installation Details按钮,会得到一个对话框。在Installed Software标签中,检查刚才选择的模块是否在这个列表中,如图2-9所示。
如果一切没问题,再检查一下Eclipse现在是否已经支持创建Maven项目。依次单击菜单栏中的File→New→Other,在弹出的对话框中,找到Maven一项,再将其展开,应该能够看到图2-10所示的对话框。
如果一切正常,说明m2eclipse已经正确安装了。
最后,关于m2eclipse的安装需要提醒的一点是,你可能会在使用m2eclipse时遇到类似这样的错误: 图2-9m2eclipse安装结果
图2-10Eclipse中创建Maven项目向导
09-10-6 上午01时14分49秒: Eclipse is running in a JRE, but a JDK is required
Some Maven plugins may not work when importing projects or updating source folders这是因为Eclipse默认是运行在JRE上的,而m2eclipse的一些功能要求使用JDK。解决方法是配置Eclipse安装目录的eclipseini文件,添加vm配置指向JDK。例如: --launcherXXMaxPermSize
256m
-vm
D:\java\jdk160_07\bin\javawexe
-vmargs
-DosgirequiredJavaVersion=15
-Xms128m
-Xmx256m26安装NetBeans Maven插件
本小节会先介绍如何在NetBeans上安装Maven插件,后面的章节中还会介绍NetBeans中具体的Maven操作。
如果正在使用NetBeans 67及以上版本,那么Maven插件已经预装了。你可以检查Maven插件安装,单击菜单栏中的工具,接着选择插件,在弹出的插件对话框中选择已安装标签,应该能够看到Maven插件,如图2-11所示。图2-11已安装的NetBeans Maven插件
如果在使用NetBeans 67之前的版本,或者由于某些原因NetBeans Maven插件被卸载了,那么就需要安装NetBeans Maven插件。下面以NetBeans 61为例,介绍Maven插件的安装。
同样,单击菜单栏中的工具,选择插件,在弹出的插件对话框中选择可用插件标签,接着在右边的搜索框内输入Maven,这时会在左边的列表中看到一个名为Maven的插件。选择该插件,然后单击下面的“安装”按钮,如图2-12所示。
图2-12安装NetBeans Maven插件
接着在随后的对话框中根据提示操作,阅读相关许可证并接受,NetBeans会自动帮我们下载并安装Maven插件,结束之后会提示安装完成。之后再单击插件对话框中的已安装标签,就能看到已经激活的Maven插件。
最后,为了确认Maven插件确实已经正确安装了,可以看一下NetBeans是否已经拥有创建Maven项目的相关菜单。在菜单栏中选择文件,然后选择新建项目,这时应该能够看到项目类别中有Maven一项。选择该类别,右边会相应地显示Maven项目和基于现有POM的Maven项目,如图2-13所示。
如果能看到类似的对话框,说明NetBeans Maven已经正确安装了。图2-13NetBeans中创建Maven项目向导
27Maven安装最佳实践
本节介绍一些在安装Maven过程中不是必须的,但十分有用的实践。
271设置MAVEN_OPTS环境变量
前面介绍Maven安装目录时我们了解到,运行mvn命令实际上是执行了Java命令,既然是运行Java,那么运行Java命令可用的参数当然也应该在运行mvn命令时可用。这个时候,MAVEN_OPTS环境变量就能派上用场。
通常需要设置MAVEN_OPTS的值为-Xms128m -Xmx512m,因为Java默认的最大可用内存往往不能够满足Maven运行的需要,比如在项目较大时,使用Maven生成项目站点需要占用大量的内存,如果没有该配置,则很容易得到javalangOutOfMemeoryError。因此,一开始就配置该变量是推荐的做法。
关于如何设置环境变量,请参考前面设置M2_HOME环境变量的做法,尽量不要直接修改mvnbat或者mvn这两个Maven执行脚本文件。因为如果修改了脚本文件,升级Maven时就不得不再次修改,一来麻烦,二来容易忘记。同理,应该尽可能地不去修改任何Maven安装目录下的文件。
272配置用户范围settingsxml
Maven用户可以选择配置$M2_HOME/conf/settingsxml或者~/m2/settingsxml。前者是全局范围的,整台机器上的所有用户都会直接受到该配置的影响,而后者是用户范围的,只有当前用户才会受到该配置的影响。
推荐使用用户范围的settingsxml,主要是为了避免无意识地影响到系统中的其他用户。如果有切实的需求,需要统一系统中所有用户的settingsxml配置,当然应该使用全局范围的settingsxml。
除了影响范围这一因素,配置用户范围settingsxml文件还便于Maven升级。直接修改conf目录下的settingsxml会导致Maven升级不便,每次升级到新版本的Maven,都需要复制settingsxml文件。如果使用~/m2目录下的settingsxml,就不会影响到Maven安装文件,升级时就不需要触动settingsxml文件。
273不要使用IDE内嵌的Maven
无论Eclipse还是NetBeans,当集成Maven时,都会安装上一个内嵌的Maven,这个内嵌的Maven通常会比较新,但不一定很稳定,而且往往也会和在命令行使用的Maven不是同一个版本。这里又会出现两个潜在的问题:首先,较新版本的Maven存在很多不稳定因素,容易造成一些难以理解的问题;其次,除了IDE,也经常还会使用命令行的Maven,如果版本不一致,容易造成构建行为的不一致,这是我们所不希望看到的。因此,应该在IDE中配置Maven插件时使用与命令行一致的Maven。
在m2eclipse环境中,单击菜单栏中的Windows,然后选择Preferences,在弹出的对话框中,展开左边的Maven项,选择Installation子项,在右边的面板中,能够看到有一个默认的Embedded Maven安装被选中了。单击Add按钮,然后选择Maven安装目录M2_HOME,添加完毕之后选择这一个外部的Maven,如图2-14所示。图2-14在Eclipse中使用外部Maven
NetBeans Maven插件默认会侦测PATH环境变量,因此会直接使用与命令行一致的Maven环境。依次单击菜单栏中的工具→选项→其他→Maven标签栏,就能看到图2-15所示的配置。 图2-15在NetBeans中使用外部Maven
28小结
本章详细介绍了在各种操作系统平台上安装Maven,并对Maven安装目录进行了深入的分析,在命令行的基础上,又进一步介绍了Maven与主流IDE Eclipse及NetBeans的集成。本章最后还介绍了一些与Maven安装相关的最佳实践。下一章会创建一个Hello World项目,带领读者配置和构建Maven项目。 Maven实战第3章Maven使用入门到目前为止,已经大概了解并安装好了Maven,现在,我们开始创建一个最简单的Hello World项目。如果你是初次接触Maven,建议按照本章的内容一步步地编写代码并执行,其中可能你会碰到一些概念暂时难以理解,不用着急,记下这些疑难点,相信本书的后续章节会帮你逐一解答。
31编写POM
就像Make的Makefile、Ant的buildxml一样,Maven项目的核心是pomxml。POM(Project Object Model,项目对象模型)定义了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。现在先为Hello World项目编写一个最简单的pomxml。
首先创建一个名为helloworld的文件夹,打开该文件夹,新建一个名为pomxml的文件,输入其内容,如代码清单3-1所示。代码清单3-1Hello World的POM
xmlns:xsi="http://wwww3org/2001/XMLSchemainstance"
xsi:schemaLocation="http://mavenapacheorg/POM/400
http://mavenapacheorg/mavenv4_0_0xsd">
400
comjuvenxumvnbook
10SNAPSHOT
Maven Hello World Project
代码的第一行是XML头,指定了该xml文档的版本和编码方式。紧接着是project元素,project是所有pomxml的根元素,它还声明了一些POM相关的命名空间及xsd元素,虽然这些属性不是必须的,但使用这些属性能够让第三方工具(如IDE中的XML编辑器)帮助我们快速编辑POM。
根元素下的第一个子元素modelVersion指定了当前POM模型的版本,对于Maven 2及Maven 3来说,它只能是400。
这段代码中最重要的是包含groupId、artifactId和version的三行。这三个元素定义了一个项目基本的坐标,在Maven的世界,任何的jar、pom或者war都是以基于这些基本的坐标进行区分的。
groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联。譬如在googlecode上建立了一个名为myapp的项目,那么groupId就应该是comgooglecodemyapp,如果你的公司是mycom,有一个项目为myapp,那么groupId就应该是commycommyapp。本书中所有的代码都基于groupId comjuvenxumvnbook。
artifactId定义了当前Maven项目在组中唯一的ID,我们为这个Hello World项目定义artifactId为helloworld,本书其他章节代码会分配其他的artifactId。而在前面的groupId为comgooglecodemyapp的例子中,你可能会为不同的子项目(模块)分配artifactId,如myapputil、myappdomain、myappweb等。
顾名思义,version指定了Hello World项目当前的版本——10SNAPSHOT。SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。随着项目的发展,version会不断更新,如升级为10、11SNAPSHOT、11、20等。65节会详细介绍SNAPSHOT,第13章会介绍如何使用Maven管理项目版本的升级发布。
最后一个name元素声明了一个对于用户更为友好的项目名称,虽然这不是必须的,但还是推荐为每个POM声明name,以方便信息交流。
没有任何实际的Java代码,我们就能够定义一个Maven项目的POM,这体现了Maven的一大优点,它能让项目对象模型最大程度地与实际代码相独立,我们可以称之为解耦,或者正交性。这在很大程度上避免了Java代码和POM代码的相互影响。比如当项目需要升级版本时,只需要修改POM,而不需要更改Java代码;而在POM稳定之后,日常的Java代码开发工作基本不涉及POM的修改。
32编写主代码
项目主代码和测试代码不同,项目的主代码会被打包到最终的构件中(如jar),而测试代码只在运行测试时用到,不会被打包。默认情况下,Maven假设项目主代码位于src/main/java目录,我们遵循Maven的约定,创建该目录,然后在该目录下创建文件com/juvenxu/mvnbook/helloworld/HelloWorldjava,其内容如代码清单3-2所示:代码清单3-2Hello World的主代码
package comjuvenxumvnbookhelloworld;
public class HelloWorld
{
public String sayHello()
{
return "Hello Maven";
}
public static void main(String[] args)
{
Systemoutprint( new HelloWorld()sayHello() );
}
}
这是一个简单的Java类,它有一个sayHello()方法,返回一个String。同时这个类还带有一个main方法,创建一个HelloWorld实例,调用sayHello()方法,并将结果输出到控制台。
关于该Java代码有两点需要注意。首先,在绝大多数情况下,应该把项目主代码放到src/main/java/目录下(遵循Maven的约定),而无须额外的配置,Maven会自动搜寻该目录找到项目主代码。其次,该Java类的包名是comjuvenxumvnbookhelloworld,这与之前在POM中定义的groupId和artifactId相吻合。一般来说,项目中Java类的包都应该基于项目的groupId和artifactId,这样更加清晰,更加符合逻辑,也方便搜索构件或者Java类。
代码编写完毕后,使用Maven进行编译,在项目根目录下运行命令 mvn clean compile会得到如下输出:[INFO] Scanning for projects…
[INFO]
------------------------------------------------------------------------
[INFO] Building Maven Hello World Project
[INFO]tasksegment: [clean, compile]
[INFO]
------------------------------------------------------------------------
[INFO] [clean:clean {execution: defaultclean}]
[INFO] Deleting directory D:\code\helloworld\target
[INFO] [resources:resources {execution: defaultresources}]
[INFO] skip non existing resourceDirectory D: \code\helloworld\src\main\resources
[INFO] [compiler:compile {execution: defaultcompile}]
[INFO] Compiling 1 source file to D: \code\helloworld\target\classes
[INFO]
------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO]
------------------------------------------------------------------------
[INFO] Total time: 1 second
[INFO] Finished at: Fri Oct 09 02:08:09 CST 2009
[INFO] Final Memory: 9M/16M
[INFO]
------------------------------------------------------------------------clean告诉Maven清理输出目录target/,compile告诉Maven编译项目主代码,从输出中看到Maven首先执行了clean:clean任务,删除target/目录。默认情况下,Maven构建的所有输出都在target/目录中;接着执行resources:resources任务(未定义项目资源,暂且略过);最后执行compiler:compile任务,将项目主代码编译至target/classes目录(编译好的类为com/juvenxu/mvnbook/helloworld/HelloWorldClass)。
上文提到的clean:clean、resources:resources和compiler:compile对应了一些Maven插件及插件目标,比如clean:clean是clean插件的clean目标,compiler:compile是compiler插件的compile目标。后文会详细讲述Maven插件及其编写方法。
至此,Maven在没有任何额外的配置的情况下就执行了项目的清理和编译任务。接下来,编写一些单元测试代码并让Maven执行自动化测试。
33编写测试代码
为了使项目结构保持清晰,主代码与测试代码应该分别位于独立的目录中。32节讲过Maven项目中默认的主代码目录是src/main/java,对应地,Maven项目中默认的测试代码目录是src/test/java。因此,在编写测试用例之前,应当先创建该目录。
在Java世界中,由Kent Beck和Erich Gamma建立的JUnit是事实上的单元测试标准。要使用JUnit,首先需要为Hello World项目添加一个JUnit依赖,修改项目的POM如代码清单3-3所示:代码清单3-3为Hello World的POM添加依赖
xmlns:xsi="http://wwww3org/2001/XMLSchemainstance"
xsi:schemaLocation="http://mavenapacheorg/POM/400
http://mavenapacheorg/mavenv4_0_0xsd">
400
comjuvenxumvnbook
10SNAPSHOT
Maven Hello World Project
junit
47
test
代码中添加了dependencies元素,该元素下可以包含多个dependency元素以声明项目的依赖。这里添加了一个依赖——groupId是junit,artifactId是junit,version是47。前面提到groupId、artifactId和version是任何一个Maven项目最基本的坐标,JUnit也不例外,有了这段声明,Maven就能够自动下载junit47jar。也许你会问,Maven从哪里下载这个jar呢?在Maven之前,可以去JUnit的官方网站下载分发包,有了Maven,它会自动访问中央仓库(http://repo1mavenorg/maven2/),下载需要的文件。读者也可以自己访问该仓库,打开路径junit/junit/47/,就能看到junit47pom和junit47jar。第6章会详细介绍Maven仓库及中央仓库。
上述POM代码中还有一个值为test的元素scope,scope为依赖范围,若依赖范围为test则表示该依赖只对测试有效。换句话说,测试代码中的import JUnit代码是没有问题的,但是如果在主代码中用import JUnit代码,就会造成编译错误。如果不声明依赖范围,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。
配置了测试依赖,接着就可以编写测试类。回顾一下前面的HelloWorld类,现在要测试该类的sayHello()方法,检查其返回值是否为“Hello Maven”。在src/test/java目录下创建文件,其内容如代码清单3-4所示:代码清单3-4Hello World的测试代码
package comjuvenxumvnbookhelloworld;
import static orgjunitAssertassertEquals;
import orgjunitTest;
public class HelloWorldTest
{
@Test
public void testSayHello()
{
HelloWorld helloWorld = new HelloWorld();
String result = helloWorldsayHello();
assertEquals( "Hello Maven", result );
}
}
一个典型的单元测试包含三个步骤:① 准备测试类及数据;② 执行要测试的行为;③ 检查结果。上述样例首先初始化了一个要测试的HelloWorld实例,接着执行该实例的sayHello()方法并保存结果到result变量中,最后使用JUnit框架的Assert类检查结果是否为我们期望的“Hello Maven”。在JUnit 3中,约定所有需要执行测试的方法都以test开头,这里使用了JUnit 4,但仍然遵循这一约定。在JUnit 4中,需要执行的测试方法都应该以@Test进行标注。
测试用例编写完毕之后就可以调用Maven执行测试。运行 mvn clean test :[INFO] Scanning for projects…
[INFO]
------------------------------------------------------------------------
[INFO] Building Maven Hello World Project
[INFO]tasksegment: [clean, test]
[INFO]
------------------------------------------------------------------------
[INFO] [clean:clean {execution: defaultclean}]
[INFO] Deleting directory D:\gitjuven\mvnbook\code\helloworld\target
[INFO] [resources:resources {execution: defaultresources}]
…
Downloading: http://repo1mavenorg/maven2/junit/junit/47/junit47pom
1K downloaded (junit47pom)
[INFO] [compiler:compile {execution: defaultcompile}]
[INFO] Compiling 1 source file to D: \code\helloworld\target\classes
[INFO] [resources:testResources {execution: defaulttestResources}]
…
Downloading: http://repo1mavenorg/maven2/junit/junit/47/junit47jar
226K downloaded (junit47jar)
[INFO] [compiler:testCompile {execution: defaulttestCompile}]
[INFO] Compiling 1 source file to D:\code\helloworld\target\testclasses
[INFO]
------------------------------------------------------------------------
[ERROR] BUILD FAILURE
[INFO]
------------------------------------------------------------------------
[INFO] Compilation failure
D:\code\helloworld\src\test\java\com\juvenxu\mvnbook\helloworld\HelloWorldTestjava:[8,5] source 13 中不支持注释
(请使用source 5 或更高版本以启用注释)
@Test
[INFO]
------------------------------------------------------------------------
[INFO] For more information, run Maven with thee switch
…不幸的是构建失败了,先耐心分析一下这段输出(为了本书的简洁,一些不重要的信息用省略号略去了)。命令行输入的是mvn clean test,而Maven实际执行的可不止这两个任务,还有clean:clean、resources:resources、compiler:compile、resources:testResources以及compiler:testCompile。暂时需要了解的是,在Maven执行测试(test)之前,它会先自动执行项目主资源处理、主代码编译、测试资源处理、测试代码编译等工作,这是Maven生命周期的一个特性。本书后续章节会详细解释Maven的生命周期。
从输出中还看到:Maven从中央仓库下载了junit47pom和junit47jar这两个文件到本地仓库(~/m2/repository)中,供所有Maven项目使用。
构建在执行compiler:testCompile任务的时候失败了,Maven输出提示我们需要使用-source 5或更高版本以启动注释,也就是前面提到的JUnit 4的@Test注解。这是Maven初学者常常会遇到的一个问题。由于历史原因,Maven的核心插件之一——compiler插件默认只支持编译Java 13,因此需要配置该插件使其支持Java 5,见代码清单3-5。代码清单3-5配置mavencompilerplugin支持Java 5
…
orgapachemavenplugins
15
15
…
该POM省略了除插件配置以外的其他部分。我们暂且不去关心插件配置的细节,只需要知道compiler插件支持Java 5的编译。现在再执行mvn clean test,输出如下:…
[INFO] [compiler:testCompile {execution: defaulttestCompile}]
[INFO] Compiling 1 source file to D: \code\helloworld\target\testclasses
[INFO] [surefire:test {execution: defaulttest}]
[INFO] Surefire report directory: D:\code\helloworld\target\surefirereports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running comjuvenxumvnbookhelloworldHelloWorldTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0055 sec
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO]
------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO]
------------------------------------------------------------------------
…我们看到compiler:testCompile任务执行成功了,测试代码通过编译之后在target/testclasses下生成了二进制文件,紧接着surefire:test任务运行测试,surefire是Maven中负责执行测试的插件,这里它运行测试用例HelloWorldTest,并且输出测试报告,显示一共运行了多少测试,失败了多少,出错了多少,跳过了多少。显然,我们的测试通过了。
34打包和运行
将项目进行编译、测试之后,下一个重要步骤就是打包(package)。Hello World的POM中没有指定打包类型,使用默认打包类型jar。简单地执行命令 mvn clean package 进行打包,可以看到如下输出:…
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
[INFO] [jar:jar {execution: defaultjar}]
[INFO] Building jar: D:\code\helloworld\target\helloworld10SNAPSHOTjar
[INFO]
------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
…类似地,Maven会在打包之前执行编译、测试等操作。这里看到jar:jar任务负责打包,实际上就是jar插件的jar目标将项目主代码打包成一个名为helloworld10SNAPSHOTjar的文件。该文件也位于target/输出目录中,它是根据artifactversionjar规则进行命名的,如有需要,还可以使用finalName来自定义该文件的名称,这里暂且不展开,后面会详细解释。
至此,我们得到了项目的输出,如果有需要的话,就可以复制这个jar文件到其他项目的Classpath中从而使用HelloWorld类。但是,如何才能让其他的Maven项目直接引用这个jar呢?还需要一个安装的步骤,执行 mvn clean install:…
[INFO] [jar:jar {execution: defaultjar}]
[INFO] Building jar: D: \code\helloworld\target\helloworld10SNAPSHOTjar
[INFO] [install:install {execution: defaultinstall}]
[INFO] Installing D:\code\helloworld\target\helloworld10SNAPSHOTjar to C:\Users\juven\m2\repository\com\juvenxu\mvnbook\helloworld\10SNAPSHOT\helloworld10SNAPSHOTjar
[INFO]
------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
…在打包之后,又执行了安装任务install:install。从输出可以看到该任务将项目输出的jar安装到了Maven本地仓库中,可以打开相应的文件夹看到Hello World项目的pom和jar。之前讲述JUnit的POM及jar的下载的时候,我们说只有构件被下载到本地仓库后,才能由所有Maven项目使用,这里是同样的道理,只有将Hello World的构件安装到本地仓库之后,其他Maven项目才能使用它。
我们已经体验了Maven最主要的命令:mvn clean compile、mvn clean test、mvn clean package、mvn clean install。执行test之前是会先执行compile的,执行package之前是会先执行test的,而类似地,install之前会执行package。可以在任何一个Maven项目中执行这些命令,而且我们已经清楚它们是用来做什么的。
到目前为止,还没有运行Hello World项目,不要忘了HelloWorld类可是有一个main方法的。默认打包生成的jar是不能够直接运行的,因为带有main方法的类信息不会添加到manifest中(打开jar文件中的METAINF/MANIFESTMF文件,将无法看到MainClass一行)。为了生成可执行的jar文件,需要借助mavenshadeplugin,配置该插件如下:
orgapachemavenplugins
121
shade
comjuvenxumvnbookhelloworldHelloWorld
plugin元素在POM中的相对位置应该在
下面。我们配置了mainClass为comjuvenxumvnbookhelloworldHelloWorld,项目在打包时会将该信息放到MANIFEST中。现在执行 mvn clean install,待构建完成之后打开target/目录,可以看到helloworld10SNAPSHOTjar和originalhelloworld10SNAPSHOTjar,前者是带有MainClass信息的可运行jar,后者是原始的jar,打开helloworld10SNAPSHOTjar的METAINF/MANIFESTMF,可以看到它包含这样一行信息:MainClass: comjuvenxumvnbookhelloworldHelloWorld现在,在项目根目录中执行该jar文件:D: \code\helloworld>javajar target\helloworld10SNAPSHOTjar
Hello Maven控制台输出为Hello Maven,这正是我们所期望的。
本小节介绍了Hello World项目,侧重点是Maven而非Java代码本身,介绍了POM、Maven项目结构以及如何编译、测试、打包等。
35使用Archetype生成项目骨架
Hello World项目中有一些Maven的约定:在项目的根目录中放置pomxml,在src/main/java目录中放置项目的主代码,在src/test/java中放置项目的测试代码。之所以一步一步地展示这些步骤,是为了能让可能是Maven初学者的你得到最实际的感受。我们称这些基本的目录结构和pomxml文件内容称为项目的骨架,当第一次创建项目骨架的时候,你还会饶有兴趣地去体会这些默认约定背后的思想,第二次,第三次,你也许还会满意自己的熟练程度,但第四、第五次做同样的事情,你可能就会恼火了。为此Maven提供了Archetype以帮助我们快速勾勒出项目骨架。
还是以Hello World为例,我们使用maven archetype来创建该项目的骨架,离开当前的Maven项目目录。
如果是Maven 3,简单地运行:mvn archetype:generate如果是Maven 2,最好运行如下命令:mvn orgapachemavenplugins:mavenarchetypeplugin:20alpha5:generate很多资料会让你直接使用更为简单的 mvn archetype:generate 命令,但在Maven 2中这是不安全的,因为该命令没有指定Archetype插件的版本,于是Maven会自动去下载最新的版本,进而可能得到不稳定的SNAPSHOT版本,导致运行失败。然而在Maven 3中,即使用户没有指定版本,Maven也只会解析最新的稳定版本,因此这是安全的。具体内容见77节。
我们实际上是在运行插件mavenarchetypeplugin,注意冒号的分隔,其格式为 groupId:artifactId:version:goal,orgapachemavenplugins 是maven官方插件的groupId,mavenarchetypeplugin 是Archetype插件的artifactId,20alpha5 是目前该插件最新的稳定版,generate是要使用的插件目标。
紧接着会看到一段长长的输出,有很多可用的Archetype供选择,包括著名的Appfuse项目的Archetype、JPA项目的Archetype等。每一个Archetype前面都会对应有一个编号,同时命令行会提示一个默认的编号,其对应的Archetype为mavenarchetypequickstart,直接回车以选择该Archetype,紧接着Maven会提示输入要创建项目的groupId、artifactId、version以及包名package。如下输入并确认:Define value for groupId: : comjuvenxumvnbook
Define value for artifactId: : helloworld
Define value for version: 10SNAPSHOT: :
Define value for package: comjuvenxumvnbook: : comjuvenxumvnbookhelloworld
Confirm properties configuration:
groupId: comjuvenxumvnbook
artifactId: helloworld
version: 10SNAPSHOT
package: comjuvenxumvnbookhelloworld
Y: : YArchetype插件将根据我们提供的信息创建项目骨架。在当前目录下,Archetype插件会创建一个名为helloworld(我们定义的artifactId)的子目录,从中可以看到项目的基本结构:基本的pomxml已经被创建,里面包含了必要的信息以及一个junit依赖;主代码目录src/main/java已经被创建,在该目录下还有一个Java类comjuvenxumvnbookhelloworldApp,注意这里使用到了刚才定义的包名,而这个类也仅仅只有一个简单的输出Hello World!的main方法;测试代码目录src/test/java也被创建好了,并且包含了一个测试用例comjuvenxumvnbookhelloworldAppTest。
Archetype可以帮助我们迅速地构建起项目的骨架,在前面的例子中,我们完全可以在Archetype生成的骨架的基础上开发Hello World项目以节省大量时间。
此外,这里仅仅是看到了一个最简单的Archetype,如果有很多项目拥有类似的自定义项目结构以及配置文件,则完全可以一劳永逸地开发自己的Archetype,然后在这些项目中使用自定义的Archetype来快速生成项目骨架。本书后面的章节会详细阐述如何开发Maven Archetype。
36m2eclipse简单使用
介绍前面Hello World项目的时候,并没有涉及IDE,如此简单的一个项目,使用最简单的编辑器也能很快完成。但对于稍微大一些的项目来说,没有IDE就是不可想象的。本节介绍m2eclipse的基本使用。
361导入Maven项目
第2章介绍了如何安装m2eclipse,现在,使用m2ecilpse导入Hello World项目。选择菜单项File,然后选择Import,我们会看到一个Import对话框。在该对话框中选择General目录下的Maven Projects,然后单击Next按钮,就会出现Import Projects对话框。在该对话框中单击Browse按钮选择Hello World的根目录(即包含pomxml文件的那个目录),这时对话框中的Projects:部分就会显示该目录包含的Maven项目,如图3-1所示。图3-1在Eclipse中导入Maven项目
单击Finish按钮之后,m2ecilpse就会将该项目导入到当前的workspace中,导入完成之后,就可以在Package Explorer视图中看到图3-2所示的项目结构。
图3-2Eclipse中导入的Maven项目结构
我们看到主代码目录src/main/java和测试代码目录src/test/java成了Eclipse中的资源目录,包和类的结构也十分清晰。当然pomxml永远在项目的根目录下,而从这个视图中甚至还能看到项目的依赖junit47jar,其实际的位置指向了Maven本地仓库(这里自定义了Maven本地仓库地址为D:\java\repository。后续章节会介绍如何自定义本地仓库位置)。
362创建Maven项目
创建一个Maven项目也十分简单,选择菜单项File→New→Other,在弹出的对话框中选择Maven下的Maven Project,然后单击Next按钮,在弹出的New Maven Project对话框中,使用默认的选项(不要选择Create a simple project选项,那样我们就能使用Maven Archetype),单击Next按钮,此时m2eclipse会提示我们选择一个Archetype。这里选择mavenarchetypequickstart,再单击Next按钮。由于m2eclipse实际上是在使用mavenarchetypeplugin插件创建项目,因此这个步骤与上一节使用archetype创建项目骨架类似,输入groupId、artifactId、version、package(暂时不考虑Properties),如图3-3所示。
图3-3在Eclipse中使用Archetype创建项目
注意,为了不和前面已导入的Hello World项目产生冲突和混淆,这里使用不同的artifactId和package。单击Finish按钮,Maven项目就创建完成了。其结构与前一个已导入的Hello World项目基本一致。
363运行mvn命令
我们需要在命令行输入如mvn clean install之类的命令来执行maven构建,m2eclipse中也有对应的功能。在Maven项目或者pomxml上右击,再在弹出的快捷菜单中选择Run As,就能看到常见的Maven命令,如图3-4所示。图3-4在Eclipse中运行默认mvn命令
选择想要执行的Maven命令就能执行相应的构建,同时也能在Eclipse的console中看到构建输出。这里常见的一个问题是,默认选项中没有我们想要执行的Maven命令怎么办?比如,默认带有mvn test,但我们想执行mvn clean test,很简单,选择Maven build以自定义Maven运行命令,在弹出对话框的Goals一项中输入我们想要执行的命令,如clean test,设置一下Name,单击Run即可。并且,下一次我们选择Maven build,或者使用快捷键“Alt+Shift+X, M”快速执行Maven构建的时候,上次的配置直接就能在历史记录中找到。图3-5所示就是自定义Maven运行命令的界面。
图3-5在Eclipse中自定义mvn命令
37NetBeans Maven插件简单使用
NetBeans的Maven插件也十分简单易用,我们可以轻松地在NetBeans中导入现有的Maven项目,或者使用Archetype创建Maven项目,还能够在NetBeans中直接运行mvn命令。
371打开Maven项目
与其说打开Maven项目,不如称之为导入更为合适,因为这个项目不需要是NetBeans创建的Maven项目。不过这里还是遵照NetBeans菜单中使用的名称。
选择菜单栏中的文件,然后选择打开项目,直接定位到Hello World项目的根目录,NetBeans会十分智能地识别出Maven项目,如图3-6所示。 图3-6在NetBeans中导入Maven项目
Maven项目的图标有别于一般的文件夹,单击打开项目后,Hello World项目就会被导入到NetBeans中,在项目视图中可以看到图3-7所示的项目结构。
NetBeans中项目主代码目录的名称为源包,测试代码目录成了测试包,编译范围依赖为库,测试范围依赖为测试库。这里也能看到pomxml,NetBeans甚至还帮我们引用了settingsxml。图3-7NetBeans中导入的Maven项目结构
372创建Maven项目
在NetBeans中创建Maven项目同样十分轻松。在菜单栏中选择文件,然后选择新建项目,在弹出的对话框中,选择项目类别为Maven,项目为Maven项目,单击“下一步”按钮之后,对话框会提示我们选择Maven原型(即Maven Archtype)。这里选择Maven快速启动原型(10),即前文提到的mavenarchetypequickstart,单击“下一步”按钮之后,输入项目的基本信息。这些信息在之前讨论Archetype及在m2eclipse中创建Maven项目的时候都仔细解释过,这里不再详述,如图3-8所示。 图3-8在NetBeans中使用Archetype创建Maven项目
单击“完成”按钮之后,一个新的Maven项目就创建好了。
373运行mvn命令
NetBeans在默认情况下提供两种Maven运行方式,单击菜单栏中的运行,可以看到生成项目和清理并生成项目两个选项。可以尝试“点击运行Maven构建”,根据NetBeans控制台的输出,就能发现它们实际上对应了mvn install和mvn clean install两个命令。
在实际开发过程中,我们往往不会满足于这两种简单的方式。比如,有时候我们只想执行项目的测试,而不需要打包,这时就希望能够执行mvn clean test命令,所幸的是NetBeans Maven插件完全支持自定义的mvn命令配置。
在菜单栏中选择工具,接着选择选项,在对话框的最上面一栏选择其他,在下面选择Maven标签栏。在这里可以对NetBeans Maven插件进行全局的配置(还记得第2章中如何配置NetBeans使用外部Maven吗?)。现在,选择倒数第三行的编辑全局定制目标定义,添加一个名为Maven Test的操作,执行目标为clean test,暂时不考虑其他配置选项,如图3-9所示。 图3-9在NetBeans中自定义mvn命令
单击“缺省保存该配置”,在Maven项目上右击,选择定制,就能看到刚才配置好的Maven运行操作。选择Maven Test之后,终端将执行mvn clean test。值得一提的是,也可以在项目上右击,选择定制,再选择目标,再输入想要执行的Maven目标(如clean package),单击“确定”按钮之后NetBeans就会执行相应的Maven命令。这种方式十分便捷,但这是临时的,该配置不会被保存,也不会有历史记录。
38小结
本章以尽可能简单且详细的方式叙述了一个Hello World项目,重点解释了POM的基本内容、Maven项目的基本结构以及构建项目基本的Maven命令。在此基础上,还介绍了如何使用Archetype快速创建项目骨架。最后讲述的是如何在Eclipse和NetBeans中导入、创建及构建Maven项目。第1章Maven简介
第2章 Maven的安装和配置
第3章Maven使用入门