Maven实战

第二章、Maven的安装和配置
首先介绍Windows上maven的安装过程:
1、安装jdk,Maven可运行在jdk1.4及以上的版本。
2、下载Maven安装包,apache-maven-3.0-bin.zip
3、将安装文件解压到指定目录,例如D:\bin\apache-maven-3.0。然后需要设置环境变量:
M2_HOME,变量值为maven的安装目录
编辑Path变量,在后面加上%M2_HOME%\bin。
4、检验maven是否安装成功:
echo %M2_HOME%
mvn -v


在Windows上更新Maven非常简单,只需要下载新的maven安装文件,解压至本地目录,然后更新M2_HOME环境变量即可。


Unix系统上Maven的安装过程:
1、检验java环境搭建情况,
echo $JAVA_HOME
java -version
2、下载maven安装文件:apache-maven-3.0-bin.tar.gz
解压安装包,tar -xvzf apache-maven-3.0-bin.tar.gz
3、设置环境变量:
export M2_HOME=/home/juven/bin/apache-maven
export PATH=$PATH:$M2_HOME/bin
4、检验maven是否安装成功:
echo $M2_HOME
mvn -v



下面解析下maven安装目录:
1、bin:该目录包含了mvn运行的脚本,这些脚本用来配置java命令,准备好classpath和相关的java系统属性,然后执行JAVA命令
2、boot:该目录只包含一个文件,该文件为plexus-classworlds-2.2.3.jar,maven使用该框架加载自己的类库。
3、conf:该目录包含了一个非常重要的文件settings.xml。直接修改该文件,就能在机器上全局的定制Maven的行为。一般情况下,我们更偏向于复制该文件至~/.m2/目录下(~表示用户目录),然后修改该文件,在用户范围定制maven的行为。
4、lib:该目录包含了maven运行时需要的JAVA类库。maven本身是分模块开发的,因此用户能看到诸如maven-core-3.0.jar、maven-model-3.0.jar之类的文件。

~指代用户目录,在用户目录下可以发现.m2文件夹。默认情况下,该文件夹下放置了Maven本地仓库.m2/repository。所有的maven构件都被存储到该仓库中,以方便重用。


默认情况下,~/.m2目录下除了repository仓库之外就没有其他目录和文件了,不过大多数maven用户需要复制M2_HOME/conf/settings.xml文件到用户目录~/.m2/settings.xml文件夹中,修改此文件只对当前用户生效。


Eclipse默认没有集成对Maven的支持。需要为Eclipse安装m2eclipse插件。下面介绍m2eclipse插件的安装步骤:书中P18页。


Maven用户可以选择配置$M2_HOME/conf/settings.xml或者~/.m2/settings.xml。前者是全局范围的,整台机器上的所有用户都会直接受到该配置的影响,而后者是用户范围的,只有当前用户才会受到该配置的影响。重点提示:推荐使用用户范围的settings.xml


重点提示:不要使用IDE内嵌的Maven,这个特别容易出问题,要在eclipse中使用自己安装的maven,下面介绍在eclipse中配置使用自己安装的maven步骤:
Windows---Preferences---展开左边maven项---选择Installation子项---右边能看到一个默认的Embedded Maven安装被选中了---单击Add按钮---选中maven安装目录M2_HOME---添加完毕之后选择这一个外部的Maven。


第三章、Maven入门

Maven项目的核心是pom.xml。POM定义了项目的基本信息,用于描述项目如何构建,声明项目依赖,等等。
project是所有pom.xml的根元素,它还声明了一些POM相关的命名空间及xsd元素。
pom.xml中最重要的是包含groupId、artifactId和version的三行。这三个元素定义了一个项目基本的坐标,在Maven的世界里,任何的jar、pom或者war都是以基于这些基本的坐标记性区分的。

groupId定义了项目属于哪个组,这个组往往和项目所在的组织或公司存在关联。
artifactId定义了当前Maven项目在组中唯一的ID。
version指定了当前项目当前的版本。。。SNAPSHOT意为快照,说明该项目还处于开发中,是不稳定的版本。
name元素声明了一个对于用户更为友好的项目名称。


maven常见命令:
mvn clean compile。clean告诉Maven清理输出目录target/,compile告诉Maven编译项目主代码。compile:compile任务,将项目主代码编译至target/classes目录。


注:如果不声明依赖范围scope,那么默认值就是compile,表示该依赖对主代码和测试代码都有效。


由于历史原因,Maven的核心插件之一——compiler插件默认只支持编译Java1.3,因此需要配置该插件使其支持JAVA5,配置代码见P33页。

mvn clean package打包命令,默认打包类型为jar。
mvn clean install 安装命令,打包并将打成的jar包安装到本地仓库中。

我们已经体验了Maven最主要的命令:mvn clean compile、mvn clean test、mvn clean package、mvn clean install。执行test之前是会先执行compile的,执行package之前是会先执行test的,而且类似的,install之前会执行package。


plugin元素在POM中的相对位置应该在<project><build><plugins>下面。


在eclipse中执行maven命令,在Maven项目或者pom.xml上右击,再在弹出的快捷菜单中选择Run As,就能看到常见的Maven命令,如果默认选项中没有我们想要执行的Maven命令,那么我们可以选择Maven build以自定义Maven运行命令,在弹出的对话框的Goals一项中输入我们想要执行的命令,如clean test。


第五章、坐标和依赖

Maven的一大功能是管理项目依赖。

Maven坐标的元素包括groupId、artigicatId、version、packaging、classifier。。

Maven是从哪里下载构件的呢?答案其实很简单,Maven内置了一个中央仓库的地址(http://repo1.maven.org/maven2),该中央仓库包含了世界上大部分流行的开元项目构件。

maven坐标详解:
groupId:定义了当前Maven项目隶属的实际项目。首先,Maven项目和实际项目不一定是一对一的关系。
artificatId:该元素定了实际项目中的一个Maven项目(模块)。推荐的做法是使用实际项目名称作为artificatId的前缀。
version:该元素定义Maven项目当前所处的版本。
packaging:该元素定义Maven项目的打包方式。
classifier:该元素用来帮助定义构建输出的一些附属构件。
上述5个元素中,groupId、aartifactId、version是必须定义的,packaging是可选的(默认为jar),而classifier是不能直接定义的。

任何一个Maven项目都需要定义自己的坐标,当这个Maven项目成为其他Maven项目的依赖的时候,这组坐标就提现了其价值。



依赖的配置:
根元素project下的dependencies可以包含一个或者多个denpendency元素,以声明一个或者多个项目依赖,每个依赖可以包含的元素有:
1、groupId、artificatId和version:依赖的基本坐标,对你任何一个依赖来说,基本坐标是最重要的,Maven根据坐标才能找到需要的依赖。
2、scope:依赖范围。
3、optional:标记依赖是否可选。
4、exclusions:用来排除传递性依赖。


下面具体讲解:
依赖范围就是用来控制依赖与这三种classpath(编译classpath、测试classpath、运行classpath)的关系,Maven有以下几种依赖范围:
compile、test、provided、runtime、system、import


传递性依赖:假设A依赖于B,B依赖于C,我们说A对于B是第一直接依赖,B对C是第二直接依赖,A对C是传递性依赖。第一直接依赖的范围和第二直接依赖的范围决定了传递性依赖的范围。。。具体参见P65的图解

Maven依赖调解的第一原则是:路径最近者优先,在依赖路径长度相等的前提下,在POM中依赖声明的顺序决定了谁会被解析使用,顺序最靠前的那个依赖优胜。


假设一种情况,项目A依赖于项目B,但是由于一些原因,不想引入传递性依赖C,而是自己显式的声明对项目C1.1.0版本的依赖。代码中使用exclusions元素声明排除依赖,exclusions可以包含一个或者多个exclusion子元素,因此可以排除一个或者多个传递性依赖,



在配置pom的时候和写代码的时候是一样的,使用常量不仅让代码变得更加简洁,更重要的是可以避免重复,在需要更改PI的值的时候,只需要修改一处,降低了错误发生的概率。同理,在pom配置中,可以定义一些常量供下面使用,例如版本号:书上P70代码清单5-12
然后在下面引入相应jar文件的时候就可以使用该版本号常量。


第六章、仓库

任何Maven项目使用任何一个构件的方式都是完全相同的。

仓库的布局:
log4j:log4j:1.2.15这一依赖,其对应的仓库路径为log4j/log4j/1.2.15/log4j-1.2.15.jar,细心的读者可以观察到,该路径与坐标的大致对应关心为groupId/artifactId/version/artifactId-version.packaging。

下面是根据构件信息生成其在仓库中的路径:
构件信息为:groupId=org.testng、artifactId=testng、version=5.8、classifier=jdk15、packaging=jar,其对应的路径为:org/testng/testng/5.8/testng-5.8-jdk5.jar

对于Maven来说,仓库分为两类,本地仓库和远程仓库,当Maven根据坐标寻找构件的时候,它首先会查看本地仓库,如果本地仓库存在此构件,则直接使用;如果本地仓库不存在此构件,或者需要查看是否有更新的构件版本,Maven就会去远程仓库查找,发现需要的构件之后,下载到本地仓库再使用。如果本地仓库和远程仓库都没有需要的构件Maven就会报错。


私服是另一种特殊的远程仓库,为了节省宽带和时间,应该在局域网内架设一个私有的仓库服务器,用气代理所有的外部远程仓库。内部项目还能部署到私服上供其他项目使用。

Maven仓库的各种类型图见书中P78页。



默认情况下,不管是在Windows还是Linux上,每个用户在自己的用户目录下都有一个路径名为.m2/repository/的仓库目录。
例如Windows机器上为  C:\Users\juven\.m2\repository\
例如Linux机器上为  home/juven/.m2/repository。。。

注意:在Linux系统中,以点(.)开头的文件或目录默认是隐藏的,可以使用ls -a命令显示隐藏文件或目录。


有时候,用户会想要自定义本地仓库目录地址。这时候,可以编辑 ~/.m2/settings.xml,设置localRepository元素的值为想要的仓库地址。。。代码示例见书中P79页。


需要注意的是,默认情况下,~/.m2/settings.xml文件是不存在的,用户需要从Maven安装目录复制$M2_HOME/conf/settings.xml文件再进行编辑。推荐不要直接修改全局目录的settings.xml。



另一种常见的情况是,将本地的仓库安装到Maven仓库中,安装命令为:mvn clean install,
Install插件的install目标将项目的构建输出文件安装到本地仓库。


当用户输入第一条Maven命令之后,Maven才会创建本地仓库。

Maven构建查找的顺序:
当Maven需要构建的时候先从本地仓库找,当Maven无法从本地仓库找到需要的构件的时候,就会从远程仓库下载构件至本地仓库,每个用户只有一个本地仓库,但可以配置访问很多远程仓库。


Maven必须知道至少一个可用的远程仓库,才能在执行Maven命令的时候下载带需要的构件。中央仓库就是这样一个默认的远程仓库,Maven的安装文件自带了中央仓库的配置。可以参考书中P80查看Maven中央仓库的配置方式。



私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用。当Maven需要下载构件爱你的时候,它从私服请求,如果私服上不存在该构建,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。。。私服图例见书中P81页
私服的优点:
1、节省自己的外网宽带。
2、加速Maven构建。
3、部署第三方构件。
4、提高稳定性,增强控制。
5、降低中央仓库的负荷。


远程仓库的配置:
在POM中配置除中央仓库外的其他远程仓库,配置代码见书中P82页。
在repositories元素下,可以使用repository子元素声明一个或者多个远程仓库,Maven自带的中央仓库使用的ID为central。



快照版本:
例如1.0.0、1.3-alpha-4和2.0是稳定的发布版本,而2.1-SNAPSHOT和2.1-20091214.221414-13是不稳定的快照版本。快照版本就是正在开发中的不稳定版本。


一些常见的仓库搜索服务(我们可以在以下几个仓库搜索服务中搜索常见的依赖包):
1、http://repository.sonatype.org/
2、http://www.jarvana.com/jarvana/
3、http://www.mvnbrowser.com
4、http://mvnrepository.com/


第七章、生命周期和插件(这章看的稀里糊涂的,以后用到了需要重新好好研究)
Maven的生命周期就是为了对所有的构件过程进行抽象和统一,Maven从大量项目和构件工具中学习和反思,然后总结了一套高度完善的、易扩展的生命周期。这个生命周期包含了项目的清理、初始化、编译、测试、打包、集成测试、验证、部署和站点生成等几乎所有构建步骤。
Maven的生命周期都是抽象的,这种思想与设计模式中的模板方法非常类似。
每个构建步骤都可以绑定一个或多个插件行为,而且Maven为大多数构建步骤编写并绑定了默认插件。例如:针对编译的插件有maven-compiler-plugin,针对测试的插件有maven-surefire-plugin等。

Maven拥有三套相互独立的生命周期,它们分别为clean、derault和site。clean生命周期的目的是清理项目,default生命周期的目的是构建项目,而site生命周期的目的是建立项目站点。
下面重点讲下生命周期里面的重点阶段:
default生命周期里面的比较重要的阶段有:
compile--编译项目的主源码。一般来说,是编译src/main /java目录下的Java文件至项目输出的主classpath目录中。
test--使用单元测试框架运行测试,测试代码不会被打包或部署。
package--接受编译好的代码,打包或可发布的格式,如jar。
install--将包安装到Maven本地仓库,供本地其他Maven项目使用
deploy--将最终的包复制到远程仓库,供其他开发人员和Maven项目使用。

从命令行执行Maven任务的最主要方式就是调用Maven的生命周期阶段。
下面以一些常见的Maven命令为例,解释其执行的生命周期阶段:
1、$mvn clean:该命令调用clean生命周期的clean阶段。实际执行的阶段为clean生命周期的pre-clean和clean阶段。
2、$mvn test:该命令调用default生命周期的test阶段。实际执行的阶段为default生命周期的validate、initialize等,直到test的所有阶段。
3、$mvn clean  install:该命令调用clean生命周期的clean阶段和default生命周期的install阶段。实际执行的阶段为clean生命周期的pre-clean、clean阶段,以及default生命周期的从validate至install的所有阶段。

由于Maven中主要的生命周期阶段并不多,而常用的Maven命令实际都是基于这些阶段简单组合而成的。

Maven的生命周期与插件相互绑定,用以完成实际的构建按任务。

由于项目的打包类型会影响构建的具体过程,因此,default生命周期的阶段与插件目标的绑定关系由项目打包类型所决定,打包类型是通过POM中的packaging元素定义的,最常见、最重要的打包类型是jar,它也是默认的打包类型。除了默认的打包类型jar之外,常见的打包类型还有war、pom、maven-plugin、ear等。
具体的default生命周期的内置插件绑定关系及具体任务见书种P101.


在POM的build元素下的plugins子元素中声明插件的使用,这样来声明插件坐标。除此之外,还有插件执行配置,executions下每个execution子元素可以用来配置执行一个任务。具体常见配置代码见书种P103。

具体的命令行插件配置、POM中插件任务配置、获取插件信息的几种方式等查看书种第七章后半部分内容。


第八章、聚合与继承

这一章没做整理,应该用到的不多。

第九章、使用Nexus创建私服
这一章很重要,实际开发中想要创建私服的时候直接书上这章内容即可。


第十二章、使用Maven构建Web应用
我们都知道,基于Java的Web应用,其标准的打包方式是WAR,WAR与JAR类似,只不过它可以包含更多的内容,如JSP文件、Servlet、Java类、web.xml配置文件、依赖JAR包、静态web资源(如HTML、CSS、JavaScript文件)等。一个典型的WAR文件目录结构示例见书中P222.
Web项目的类及资源文件同一般JAR项目一样,默认位置是src/main/java和src/main/resources,测试类及测试资源文件的默认位置是src/test/java和src/test/resources/。Web项目比较特殊的地方在于:它还有一个Web资源目录,其默认位置是src/main/webapp/。一个典型的Web项目的Maven目录结构示例见书中P223.

在src/main/webapp目录下,必须包含一个子目录WEB-INF,该子目录还必须要包含web.xml文件。src/main/webapp目录下的其他文件和目录包含html、jsp、css、JavaScript等,它们与WAR包中的Web资源完全一致。

有一点需要注意的是,war包中有一个lib目录包含所有依赖jar包,但Maven项目结构中没有这样一个目录,这是因为依赖都配置在POM中,Maven在用war方式打包的时候会根据POM的配置从本地仓库复制相应的jar文件。


在一些web项目中,读者可能会看到finalName元素的配置。该元素用来标识项目生成的主构件的名称,该元素的默认值已在超级POM中设定,值为${project.artificatId}-${project.version},因此代码清单12-8对应的主构件名称为account-web-1.0.0-SNAP-SHOT.war。不过,这样的名称显然不利于部署,不管是测试环境还是最终产品环境,我们都不想在访问页面的时候输入沉长的地址,因此我们会需要名字更为简洁的war包。这时可以如下所示配置finalName元素:
<finalName>account</finalName>
经过此配置后,项目生成的war包名称就会成为account.war,更方便部署。

第十四章、灵活的构建【全书重中之重,用的最多的章节】
Maven为了支持构建的灵活性,内置了三大特性,即属性、Profile、和资源过滤。

一、Maven属性
这可能是最常见的使用Maven属性的方式了,通过<properties>元素用户可以自定义一个或多个Maven属性。然后在POM的其他地方使用${属性名称}的方式引用该属性,这个做法是最大意义在于消除重复。

常见的Maven属性有6类:
1、内置属性:主要有两个常用内置属性-----${basedir}表示项目根目录,即包含pom.xml文件的目录;${version}表示项目版本。
2、POM属性:用户可以使用该类属性引用POM文件中对应元素的值。例如${project.artifactId}就对应了<project><artifictId>元素的值,常见的POM属性包括:
${project.build.sourceDirectory}:项目的主源码目录,默认为src/main/java/
${project.build.directory}:项目构建输出目录,默认为target/
${project.outputDirectory}:项目主代码编译输出目录,默认为target/classes/
${project.groupId}:项目的groupId
${project.artifactId}:项目的artifactId
${project.version}:项目的version,与${version}等价
${project.build.finalName}:项目打包输出文件的名称,默认为${project.artificatId}-${project.version}

3、自定义属性:用户可以在POM的<properties>元素下自定义Maven属性。例如:
<project>
...
<properties>
<my.prop>hello</my.prop>
</properties>
...
</project>
4、settings属性:与POM属性同理,用户使用以settings.开头的属性引用settings.xml文件中XML元素的值,如常用的${settings.localRepository}指向用户本地仓库的地址。
5、Java系统属性:所有Java系统属性都可以使用Maven属性引用,例如${user.home}指向了用户目录。用户可以使用mvn help:system查看所有的Java系统属性。
6、环境变量属性:所有环境变量都可以使用以env.开头的Maven属性引用。例如${env.JAVA_HOME}指代了JAVA_HOME环境变量的值。用户可以使用mvn help: system查看所有的环境变量。

Maven构建环境的差异:
Maven的答案是针对不同的环境生成不同的构件。也就是说,在构建项目的过程中,Maven就已经将这种差异处理好了。


为了应对环境的变化,首先需要使用Maven属性将这些将会发生变化的部分提取出来。在上一节的数据库配置中,连接数据库使用的驱动类、URL、用户名和密码都可能发生变化,因此用Maven属性取代它们:
database.jdbc.driverClass = ${db.driver}
...
...
这里定义了4个Maven属性:db.driver......,它们的命名是任意的,读者可以根据自己的实际情况定义最合适的属性名称。
既然使用了Maven属性,就应该在某个地方定义它们。14.1节介绍过如何自定义Maven属性,这里要做的是使用一个额外的profile将其包裹,代码见书中P263
这里只是使用了一个ID为dev的profile,其目的是将开发环境下的配置与其他环境区别开来。
有了属性定义,配置文件中也使用了这些属性,一切OK了吗?还不行。读者要留意的是,Maven属性默认只有在POM中才会被解析。也就是说,${db.username}放到POM中会变成test,但是如果放到src/main/resources/目录下文件中,构建的时候它将仍然还是${db.username}。因此,需要Maven解析资源文件中的Maven属性。
资源文件的处理其实是maven-resources-plugin做的事情,通过一些简单的POM配置,该插件就能够解析资源文件中的Maven属性,即开启资源过滤。
Maven默认的主资源目录和测试资源目录的定义是在超级POM中。要为资源目录开启过滤,只要在此基础上添加一行filtering配置即可,如下代码:
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
开启过滤

读者可能还会从上述代码中意识到,主资源目录和测试资源目录都可以超过一个,虽然会破坏Maven的约定,但Maven允许 用户声明多个资源目录,并且为每个资源目录提供不同的过滤配置。

到目前为止一切基本就绪了,我们将数据库配置的变化部分提取成了Maven属性,在POM的profile中定义了这些属性的值,并且为资源目录开启了属性过滤。最后,只需要在命令行激活profile,Maven就能够在构建项目的时候使用profile中属性值替换数据库配置文件中的属性引用。命令如下:
$mvn clean install -P dev
mvn的-P参数表示在命令行激活一个profile。这里激活了id为dev的profile。构建完成后,输出的目录中的数据库配置就是开发环境的配置了。


Maven支持很多种激活Profile的方式,下面讲解6种:
1、命令行激活:
用户可以使用mvn命令行参数-P 加上profile的id来激活profile,多个id之间以逗号分隔。例如:下面的命令就激活了dev-x和dev-y两个profile:
$ mvn clean install -Pdev-x,dev-y

2、settings文件显示激活
如果用户希望某个profile默认一直处于激活状态,就可以配置settings.xml文件的active-Profiles元素,表示其配置的profile对于所有项目都处于激活状态。
3、系统属性激活法:
用户可以配置当某系统属性存在的时候,自动激活profile,如代码见书P267。
这种方式也等同于命令行激活,如下面的命令:
$ mvn clean install -Dtest = x
表示当系统存在属性test并且值等于x才激活profile
4、操作系统环境激活
Profile还可以自动根据操作系统环境激活,如果构建在不同的操作系统有差异,用户完全可以将这些差异写进profile,然后配置他们自动基于操作系统环境激活,如代码P267.
5、文件存在与否激活;
Maven能够根据项目中某个文件存在与否来决定是否激活profile。如代码P268。
6、默认激活:
用户可以在定义profile的时候指定其默认激活。不过需要注意的是,如果POM中有任何一个profile通过以上其他任意一种方式被激活了,所有的默认激活配置都会失效。

maven-help-plugin提供了一个目标帮助用户了解当前激活的profile:
$mvn help:active-profiles
提供了另一个目标用来列出当前所有的profile:
$mvn help:all-profiles


重点:
profile的种类:
1、pom.xml:很显然,pom.xml中声明的profile只对当前项目有效。
2、用户setings.xml:用户目录下.m2/settings.xml中的profile对本级上该用户所有的Maven项目有效
3、全局settings.xml:Maven安装目录下conf/setings.xml中的profile对本机上所有的Maven项目有效
4、profiles.xml:还可以在项目根目录下使用一个额外的profiles.xml文件来声明profile,不过该特性已经在Maven3中被移除。建议用户将这类profile移到settings.xml中。



第十六章、m2eclipse
这章非常重要,在实际开发中用到的最多,用到的时候直接看书即可,内容不算太多

你可能感兴趣的:(maven)