Maven学习

来源:互联网 发布:魔蝎数据20-0是什么 编辑:程序博客网 时间:2024/06/04 18:57

  之前自己零零散散的学了点maven,最近做完课设,感觉没什么事,决定找本<<maven实战>>仔细学学,说实话,看完之后感觉里面介绍的很多东西都是一般程序员用不到的,建议大家对于这本书不用细学,基本理解maven的思想即可(毕竟是个工具软件),里面具体某些插件的具体使用还是等到用到时再去学吧,现在学到时用时也忘了。

  自己在这里整理下。


安装Maven

①.下载Maven的安装包进行解压

②.配置环境变量

在系统变量中新建一个变量,变量名为M2_HOME,变量值为Maven的安装目录,接着在系统变量中找到

Path变量,在变量的末尾加上%M2_HOME%\bin(注意多个值需要用分号隔开)


文件目录介绍:

bin:该目录包含了mvn运行所需要的脚本

boot: 包含一个文件,plexus-classworlds-2.2.3.jar是一个类加载器框架

conf: 包含一个settings.xml,在机器上全局地定制maven的行为,平时使用的时候更加偏爱将该文件复制到~/.m2/目录下,然后修改该文件,在用户范围内定制Maven行为

lib:包含了所有Maven运行时需要的Java类库


配置用户范围settings.xml:

$ M2_HOME/conf/settings.xml(全局) 或者 ~/.m2/settings.xml(用户范围)

tip:不要使用IDE内嵌的MAVEN, 当集成Maven时,都会安装上一个内嵌,这个版本较新,不一定稳定


POM介绍:

POM(Project Object Model, 项目对象模型)

modelVersion指定了当前POM模型的版本,对于maven2和maven3它只能是4.0.0


坐标:

groupId,artifactId和version是一个项目基本的坐标,用来进行区别项目,并且是仓库中查询相应的路径。


坐标详解:

groupId:定义当前Maven项目隶属的实际项目,Maven项目和实际项目不一定是一对一的关系   (推荐:com.公司名.项目名)

artifactdId:该元素定义实际项目中的一个Maven项目(模块),推荐的做法是以实际项目名称作为artifactdId的前缀  (推荐:项目名-模块名)

version:该元素定义Maven项目当前所处的版本

//name:声明一个对于用户更为友好的项目名称(这个不属于坐标)

packaging:该元素定义Maven项目的打包方式

classifier:该元素用来帮助定义构建输出的一些附属构件。

tip:Maven的核心插件-compiler插件默认只支持编译Java1.3,很多时候需要配置该插件使其支持java1.5

配置代码

<build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactdId>maven-compiler-plugin</artifactdId><configuration><source>1.5</source><target>1.5</target></configuration></plugin></plugins></build>

使用Archetype生成项目骨架(IDE中的Maven module已经帮我们实现了)

Archetype帮助我们快速勾勒出项目骨架 mvn archetype:generate(maven3版本)


依赖范围:

Maven在编译项目的时候需要使用一套classpath,测试的时候使用另外一套classpath,最后运行的时候会使用另一套classpath

①compile:编译依赖范围,是默认的范围,对于编译,测试,运行三种classpath都有效

②test:测试依赖范围, 只对于测试classpath有效

③provided:以提供依赖范围,运行测试有效,运行时无效(servlet-api)

④runtime:运行、测试时有效范围,编译的时候无效

⑤system:和provided的范围一样,往往于本机绑定


依赖的传递性:

依赖是具有传递性的,项目有一个compile范围的spring-core依赖,spring-core有一个compile范围的commons-loggings范围,那么commons-loggings就是项目的compile依赖


依赖调解:

如果A到B的依赖有两条不同的依赖路径,并且两条路径上有两个不同的版本,

调解的第一原则:路径较近的优先,

第二原则是:第一声明者优先。

如果不想引入依赖性依赖C,而是自己显示地声明对于项目C依赖的排除,代码中使用exclusion元素声明排除依赖,exclusions可以声明多个exclusion子元素,因此可以排除一个或者多个传递性依赖,声明exclusion的时候只需要groupId和artifactId, 不需要version元素。


常量使用:

有时我们需要将一个框架的多个包的版本统一(比如spring中),此时便可以引入常量,在<properties>中定义常量,引用的时候用${springframework.version}


仓库:

任何一个构件都有其唯一的坐标,仓库中的路径与坐标的大致对应关系为

groupId/artifactId/version/artifactId-version.packging

packaging决定了构件的扩展名

Maven是基于简单文件系统存储的,我们也理解了其存储方式,当遇到一些与仓库相关的问题时,

可以很方便地查找相关文件,方便定位问题


仓库的分类:

仓库大致可以分为两类,本地仓库和远程仓库。(Maven会先在本地仓库进行查找,如果没有就去远程仓库下载到本地,如果本地仓库和远程仓库都没有需要的构件,Maven就会报错)

私服是另一种特殊的远程仓库,为了节省带宽和时间,应该在局域网内架设一个私有的仓库服务器


本地仓库:

先将settings.xml文件移到你想设置为仓库的文件夹下,然后修改<localRepository>的值,只有当依赖被下载到本地仓库中,才能被其他Maven项目使用,mvn clean install可以将本地项目放入本地仓库中


中央仓库:

中央仓库就是这样一个默认的远程仓库,Maven的安装文件自带了中央仓库的配置。$M2_HOME/lib/maven-2.2.1-uber.jar/org/apache/maven/model/pom-4.0.0.xml

<repositories><repository><id>central</id><name>……</name><url>……</url></repository></repositories>

私服(如今最为流行的Maven私服软件就是Nexus):

私服是一种特殊的远程仓库,它是架设在局域网内的仓库服务,私服代理广域网上的远程仓库,供局域网内的Maven用户使用,当Maven需要下载构件的时候,它从私服请求,如果私服上存在该构件,则从外部的远程仓库下载,缓存在私服上之后,再为Maven的下载请求提供服务。

私服的优点:

①节省自己的外网带宽

②加速Maven构建

③部署第三方构件(比如一些因为版权无法部署在公共仓库中的构件)

④提高稳定性,增强控制

⑤降低中央仓库的负荷


远程仓库的设置:

<repositories><repository>……</repository></repositories>

可以用repository子元素声明一个或者多个远程仓库

远程仓库的认证:大部分远程仓库无须认证就可以访问,但有些远程仓库需要认证才能访问一些远程仓库,servers元素及其server子元素配置仓库认证信息。

部署至远程仓库:

私服的一大作用是部署第三方构件,包括组织内部生成的构件以及一些无法从外部仓库直接获取的构件,配置distributionManagement元素,distributionManagement包含repository和snapshotRepository子元素,前者代表发布版本构件的仓库,后者代表快照版本的仓库配置正确后,在命令运行mvn clean deploy, Maven就会将项目构建输出的构件部署到配置对应的远程仓库

依赖的寻找方式:

(1)当依赖的范围是system的时候,Maven直接从本地文件系统解析构件
(2)根据坐标,常识直接从本地仓库寻找构件,如果发现相应构件,则解析成功
(3)本地仓库不存在的情况下,如果依赖的版本是显式的发布版本构件,则遍历所有的远程仓库;
(4)如果依赖的版本是RELEASE或者LAREST,将其与本地仓库的对应元数据合并后,计算出RELEASE或者LATEST真是的值。
(5)如果依赖的版本是SNAPSHOT,将其与本地仓库的对应元数据合并后,得到最新快照版本的值。
(6)如果最后解析得到的构件版本是时间戳格式的快照,并使用该非时间戳格式的构件

tip:在依赖中声明使用LATEST和RELEASE是不推荐的做法,因为Maven随时都可能解析不同的构件


生命周期:
在maven出现之前,项目部署的生命周期就已经存在,软件开发人员每天都在对项目进行清理,编译,测试及部署
Maven的生命周期就是为了对所有的构建过程进行抽象和统一
生命周期包含了项目的清理,初始化,编译,测试,打包,集成测试,验证,部署和站点生成


生命周期:

maven有三套相互独立的生命周期,它们分别为clean,default和site
clean生命周期的目的是清理项目
default声明周期的目的是构建项目
site生命周期的目的是建立项目站点
每个生命周期包含一些阶段,这些阶段是有顺序的,并且后面的阶段依赖于前面的阶段
clean的生命周期   包含的阶段有pre-clean, clean, post-clean
当用户调用clean的时候,pre-clean和clean阶段会得以顺序执行;当用户调用post-clean的时候,pre-clean, clean和post-clean会得以顺序执行

Clean生命周期
三个阶段:
①pre-clean执行一些清理前需要完成的工作
②clean清理上一次构件生成的文件
③post-clean执行一些清理后需要完成的工作


default生命周期
default生命周期定义了真正构建时所需执行的所有步骤
1.validate
2.initialize
3.generate-sources
4.process-sources 处理项目主资源文件
5.generate-resources
6.process-rources
7.compile 编译项目的主源码
8.process-classes
9.generate-test-sources
10.process-test-sources 处理项目测试资源文件
11.generate-test-resources
12.process-test-resources 
13.test-compile 编译项目的测试代码
14.process-test-classes 
15.test 使用单元测试框架运行测试
16.prepare-package
17.package接受编译好的代码
18.pre-integration-test
19.integration-test
20.post-integration-test
21.verify
22.install 将包安装到Maven本地仓库,供地方其他Maven项目使用
23.deploy 将最终的包复制到远程仓库,供其他开发人员和Maven项目使用


site生命周期
site生命周期的目的是建立和发布项目站点,Maven能够基于POM所包含的信息,自动生成一个友好的站点
①pre-site执行一些在生成项目站点之前需要完成的工作
②site生成项目站点文档
③post-site执行一些在生成项目站点之后需要完成的工作
④site-deploy将生成的项目站点发布到服务器上


命令行与生命周期
从命令执行Maven任务的最主要方式就是调用Maven的生命周期阶段
$mvn clean该命令调用clean生命周期的clean阶段
$mvn test 该命令调用default生命周期的test阶段
$mvn clean install 该命令调用clean生命周期的clean阶段和default生命周期的install阶段
$mvn clean deploy site-deploy 该命令调用clean生命周期的clean阶段和default生命周期的install阶段
实际执行的阶段为clean生命周期的pre-clean,clean阶段,以及default生命周期的从validate至install的所有阶段。


插件

插件目标:
Maven的核心仅仅定义了抽象的生命周期,具体的任务是交由插件完成的,插件以独立的构件形式存在,因此,Maven核心的发布包只有不到3MB的大小,Maven会在需要的时候下载并使用插件,对于插件本身,为了能够复用代码,它往往能够完成多个任务

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

内置绑定:
为了能让用户几乎不用任何配置就能构建Maven项目,Maven在核心为一些主要的生命周期阶段绑定了很多插件的目标,clean生命周期仅有pre-clean clean 和 post-clean 三个阶段,其中的clean与maven-clean-plugin:clean绑定site生命周期有pre-site, site, post-site和site-deploy四个阶段,其中,site和maven-site-plugin:site相互绑定对于default生命周期与插件目标的绑定关系就显得复杂一些。
default生命周期有很多其他阶段,默认它们没有绑定任何插件,因此也没有任何实际行为

除了基本的插件坐标声明外,还有插件执行配置,executions下每个execution字元素可以用来配置执行一个任务,通过phase配置,将其绑定到verify生命周期阶段上,再通过goals配置制定要执行的插件目标。有时候,即使不通过phase元素配置生命周期阶段,插件目标也能够绑定到生命周期中去,这是因为,在很多插件的目标在编写时已经定义了默认绑定阶段

插件配置
完成了插件和生命周期的绑定之后,用户可以配置插件目标的参数,进一步调整插件目标所执行的任务,以满足项目的需求,在命令行插件配置,在日常的Maven使用中,我们会经常从命令行输入并执行Maven命令。很多插件目标的参数都执行从命令行配置,用户可以在Maven命令中使用-D参数,并伴随一个参数键=参数值的形式,来配置插件目标的参数。

eg: mvn -install -Dmaven.test.skip=true (并不是所有的插件参数都适合从命令行配置,有些参数的值从项目创建到项目发布都不会改变)


POM中插件全局配置
用户可以在声明插件的时候,对此插件进行一个全局的配置。也就是说,所有该基于该插件目标的任务,都会使用这些配置可以在插件的声明中进行全局配置
eg:

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.1</version><configuration><source>1.5</source><target>1.5</target></configuration></plugin>


获取插件信息:
当遇到一个构件任务的时候,用户还需要知道去哪里寻找合适的插件,以帮助完成任务。找到正确的插件之后,还要详细了解该插件的配置点,基本上所有主要的Maven插件都来自Apache和Codehaus。

使用maven-help-plugin描述插件:

可以借助maven-help-plugin来获取插件的详细信息   格式:mvn help: describe-Deluigin = groupId:artifactId:version


目标前缀:

其作用是方便在命令行直接运行插件

maven-compiler-plugin的目标前缀就是compiler, mvn命令后面可以添加一个或者多个goal和phase, 他们分别是指插件目标和生命周期阶段,为了方便用户使用和配置插件,Maven不需要用户提供完整的插件坐标信息就可以解析得到正确的插件。


插件仓库:
插件构件同样基于坐标存储在Maven仓库中,在需要的时候,Maven会从本地仓库寻找插件,如果不存在,则从远程仓库查找,Maven会区别对待依赖的远程仓库与插件的远程仓库,配置的远程仓库,只对一般依赖有效果,当Maven需要的插件在本地仓库不存在时,他就不会去这些远程仓库中查找,插件的远程仓库使用pluginRepoositories和pluginRepository配置


解析插件版本:
同样是为了简化插件的配置和使用,在用户没有提供插件版本的情况下,1Maven会自动解析插件版本,Maven中存在一个超级POM,其中为核心插件设定了版本,超级POM是所有Maven项目的父POM,所有项目都继承了这个超级POM的配置,因此,即使用户不加任何配置,Maven使用核心插件的时候,它们的版本就已经确定了,
如果用户使用某个插件没有设定版本,而这个插件又不属于核心插件的范畴,Maven就会去检查所有仓库中可用的版本,然后做出选择,latest表示所有仓库中该构件的最新版本,而release表示最新的非快照版本。


聚合和继承


聚合:

当把Maven应用到实际项目中的时候,也需要将项目分成不同的模块
我们会想要一次构建两个项目,而不是到两个模块的目录下分别执行mvn命令
如果我们想聚合两个项目, 我们可以新建一个Maven项目将两个项目聚合起来
对于聚合模式来说,其打包方式packaging的值必须为pom,否则就无法构建
POM的name字段是为了给项目提供一个更容易阅读的名字
modules, 这是实现聚合的最核心的配置
一般来说,为了方便快速定位内容,模块所处的目录名称应当与其artifactId一致

eg:

<module>../account-email</module>

<module>../account-persist</module>


继承:

继承的打包方式也是pom,这一点需要额外注意,在子组件中需要声明<parent>元素,其中包含<groupId> <artifactId> <version> <relativePath>

可继承的POM元素:groupId和version是可以被继承的


依赖管理:
可继承元素列表包含了dependencies元素,说明依赖是会被继承的,Maven提供的dependencyManagement元素既能让子模块继承到父模块的依赖配置,又能保证子模块依赖使用的灵活性。dependencyManagement元素下的依赖声明不会引入实际的依赖,不过它能够约束dependenies下的依赖使用,dependencyManagement声明的依赖既不会给父模块引入依赖,也不会给他得的子模块引入依赖,如果想在子模块中引入这些元素,只需要声明groupId和artifactId就能获得对应的依赖信息,使用这种依赖管理机制似乎不能减少太多的POM配置,不过笔者还是强烈推荐采用这种方法。
其主要原因在于在父POM中使用dependencyManagement声明依赖能够统一项目范围中依赖的版本。与dependencyManagement相似的还有pluginManagement,用法都是相似的


聚合与继承的关系:
前者主要是为了方便快速构件项目,后者主要是为了消除重复配置,聚合pom与继承关系中的父POM的packing都必须是pom,可以将聚合和继承融合起来使用


约束由于配置:(在java中应该很常见)
Ant中很多东西都需要进行配置,但是在Maven中是已经被约定的东西
源码目录为 src/main/java/
编译输出目录为 target/classes/
打包方式为 jar
包输出目录为 target/
遵循约定虽然损失了一定的灵活性,用户不能随意安排目录结构,但是能减少配置,更重要的是,准讯约定能够帮助用户遵守构建标准
如果没有约定,项目可能会使用各种各样的目录结构
如果想改变这种约定的话,可以直接<project>中加入<build>元素进行配置
其实这些约定都是在超级POM中配置好的



0 0