首页 > 代码库 > Maven学习笔记
Maven学习笔记
1.Maven安装
Maven和ant同为apache出版的构建工具,与gradle是一类东西,与C语言中的make是同一类产品.从apache官网上下载maven的zip安装包,解压即可使用,需要把解压后的bin目录添加到环境变量中去.
Eclipse是自带maven的,如果不想使用eclipse的内置maven,可以在preference->maven->installations中进行设置.
2.最简的pom.xml文件
pom的意思是project object model项目对象模型
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jenkov</groupId> <artifactId>java-web-crawler</artifactId> <version>1.0.0</version></project>
其中,modelVersion表示正在使用的pom模型版本,groupId表示项目名称,artifactId表示模块名称,一个项目可以包含多个模块.
3.pom的继承
一个pom可以继承自父pom,它可以继承父pom的dependencies,要想让一个pom继承另一个pom,可以使用parent标签来声明父pom
<project xmlns=”http://maven.apache.org/POM/4.0.0″xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”xsi:schemaLocation=”http://maven.apache.org/POM/4.0.0http://maven.apache.org/xsd/maven-4.0.0.xsd”> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.codehaus.mojo</groupId> <artifactId>my-parent</artifactId> <version>2.0</version> <relativePath>../my-parent</relativePath> </parent> <artifactId>my-project</artifactId> ...</project>
子pom中的值会覆盖父pom中的值.因为pom的继承关系,最终的pom成为有效pom,可以通过mvn help:effective-pom命令来查看最终的pom.
每一个pom.xml默认继承super pom,super pom内容如下:
<project> <modelVersion>4.0.0</modelVersion> <name>Maven Default Project</name> <repositories> <repository> <id>central</id> <name>Maven Repository Switchboard</name> <layout>default</layout> <url>http://repo1.maven.org/maven2</url> <snapshots> <enabled>false</enabled> </snapshots> </repository> </repositories> <pluginRepositories> <pluginRepository> <id>central</id> <name>Maven Plugin Repository</name> <url>http://repo1.maven.org/maven2</url> <layout>default</layout> <snapshots> <enabled>false</enabled> </snapshots> <releases> <updatePolicy>never</updatePolicy> </releases> </pluginRepository> </pluginRepositories> <build> <directory>target</directory> <outputDirectory>target/classes</outputDirectory> <finalName>${artifactId}-${version}</finalName> <testOutputDirectory>target/test-classes</testOutputDirectory> <sourceDirectory>src/main/java</sourceDirectory> <scriptSourceDirectory>src/main/scripts</scriptSourceDirectory> <testSourceDirectory>src/test/java</testSourceDirectory> <resources> <resource> <directory>src/main/resources</directory> </resource> </resources> <testResources> <testResource> <directory>src/test/resources</directory> </testResource> </testResources> </build> <reporting> <outputDirectory>target/site</outputDirectory> </reporting> <profiles> <profile> <id>release-profile</id> <activation> <property> <name>performRelease</name> </property> </activation> <build> <plugins> <plugin> <inherited>true</inherited> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <inherited>true</inherited> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <executions> <execution> <id>attach-javadocs</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> <plugin> <inherited>true</inherited> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-deploy-plugin</artifactId> <configuration> <updateReleaseInfo>true</updateReleaseInfo> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project>
4.maven的配置
maven配置文件中的配置相当于全局配置,对于所有的pom.xml都是有效的.在配置文件settings.xml中可以配置:
-本地仓库的路径,默认为~/.m2
-当前编译选项
-其他一些配置
settings.xml有两个:一个是%Maven_Home%/conf/settings.xml,另一个是~/.m2/settings.xml.后者会覆盖前者的设置.
5.运行maven
maven构建项目有三个概念:生命周期,阶段,目标.maven内置三个生命周期,一个生命周期包括多个阶段,一个阶段包括多个目标.
运行maven只需要输入mvn命令,maven就会自动查找当前目录下的pom.xml并按照要求进行执行.
mvn命令还可以带一些参数,参数包括阶段和目标.
例如install就是一个阶段,它是在target目录中生成jar文件并将jar文件复制到maven本地仓库中去(即~/.m2目录中).执行install阶段就会默认把install之前的阶段全部执行,命令为mvn install
可以向mvn传递多个参数,表示执行多个阶段,例如mvn clean install,先进行clean把target中生成的jar删除,然后再执行install.
可以让mvn执行某个目标,命令形式为
mvn 阶段名:目标名
例如mvn dependencies:copy-dependencies
6.maven项目的目录结构
maven遵循”约定大于配置”原则,对目录有默认的组织,如果不按照默认的来,就需要指明src目录,target目录等.
- src - main - java - resources - webapp - test - java - resources- target
target目录是maven创建的,执行mvn clean命令之后target目录被清空.
7.项目依赖
项目A依赖项目B,项目B依赖项目C.众多的项目形成一个有向无环图(DAG),每一个项目相当于一个结点,每一条有向边表示一个依赖关系.如果要使用B.jar,不下载C.jar肯定会报错.使用maven,就可以自动推导出项目所依赖的全部jar包,解决项目依赖问题是maven的重要作用之一.maven会自动下载所需jar包到本地仓库中,在pom.xml中进行如下配置
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.jenkov.crawler</groupId> <artifactId>java-web-crawler</artifactId> <version>1.0.0</version> <dependencies> <dependency> <groupId>org.jsoup</groupId> <artifactId>jsoup</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.1</version> <scope>test</scope> </dependency> </dependencies> <build> </build></project>
有的时候,指定的依赖在Maven的中央仓库里没有。你可以直接下载这些依赖,然后放到Maven的本地仓库。这些依赖必须放到与groupId、 artifactId和version匹配的子目录中。用/替换所有的点(.)并且使用/分隔groupId、artifactId和version,这就是与该依赖匹配的子目录。
上面示例中的两个依赖将会被放到以下子目录中:
MAVEN_REPOSITORY_ROOT/junit/junit/4.8.1
MAVEN_REPOSITORY_ROOT/org/jsoup/jsoup/1.7.1
Maven仓库分为三种:本地仓库(即~/.m2),远程仓库(自己建立的maven服务器),中心仓库(http://mvnrepository.com/).
8.外部依赖
有时只有一个jar包而没有它的groupId和artifactId,并且三种maven仓库中都没有这个jar包项目,但当前项目依赖这个jar包,这种依赖叫做外部依赖,可以用如下配置指定外部依赖.
<dependency> <groupId>mydependency</groupId> <artifactId>mydependency</artifactId> <scope>system</scope> <version>1.0</version> <systemPath>${basedir}\war\WEB-INF\lib\mydependency.jar</systemPath></dependency>
这种方式需要在每一个maven工程的pom.xml中这么写,这样岂不是十分麻烦.一种解决方案是把第三方jar包安装到本地maven仓库中去.
mvn install:install-file -Dfile= -DgroupId= -DartifactId= -Dversion= -Dpackaging=
在这个命令中,需要手动提供groupId,artifactId等,如果第三方jar包有相应的pom.xml可以使用如下命令:
mvn install:install-file -Dfile= -DpomFile=
9.快照依赖
快照依赖指的是那些还在开发中的依赖(jar包)。与其经常地更新版本号来获取最新版本,不如你直接依赖项目的快照版本。快照版本的每一个build版本都会被下载到本地仓库,即使该快照版本已经在本地仓库了。总是下载快照依赖可以确保本地仓库中的每一个build版本都是最新的。
在pom文件的最开头(设置groupId和artifactId的地方),在版本号后追加-SNAPSHOT,则告诉Maven你的项目是一个快照版本。如:
<version>1.0-SNAPSHOT</version>
可以看到加到版本号后的-SNAPSHOT。
在配置依赖时,在版本号后追加-SNAPSHOT表明依赖的是一个快照版本。如:
<dependency> <groupId>com.jenkov</groupId> <artifactId>java-web-crawler</artifactId> <version>1.0-SNAPSHOT</version></dependency>
追加在version后的-SNAPSHOT告诉Maven这是一个快照版本.
可以在Maven配置文件中设置快照版本下载的频率.
10.maven仓库
Maven仓库就是存储jar包和一些元数据信息的目录。其中的元数据即pom文件,描述了该jar包属于哪个项目,以及jar包所需的外部依赖。该元数据信息使得Maven可以递归地下载所有的依赖,直到整个依赖树都下载完毕并放到你的本地仓库中。查找依赖时,首先是本地仓库,然后是中央仓库,最后,如果pom文件中配置了远程仓库,则会去远程仓库中查找。
(1) 本地仓库
本地仓库默认路径为~/.m2,可以在%MAVEN_HOME%/conf/settings.xml中设置本地仓库路径
<settings>
<localRepository>
d:\data\java\products\maven\repository
</localRepository>
</settings>
可以通过mvn install命令构建自己的项目并安装到本地仓库中去.
(2)中央仓库
Maven的中央仓库由Maven社区提供。默认情况下,所有不在本地仓库中的依赖都会去这个中央仓库查找。然后Maven会将这些依赖下载到你的本地仓库。访问中央仓库不需要做额外的配置。
(3)远程仓库
远程仓库是位于web服务器上的一个仓库,Maven可以从该仓库下载依赖,就像从中央仓库下载依赖一样。远程仓库可以位于Internet上的任何地方,也可以是位于本地网络中。
远程仓库一般用于放置组织内部的项目,该项目由多个项目共享。比如,由多个内部项目共用的安全项目。该安全项目不能被外部访问,因此不能放在公开的中央仓库下,而应该放到内部的远程仓库中。
远程仓库中的依赖也会被Maven下载到本地仓库中。
可以在pom文件里配置远程仓库。将以下的xml片段放到属性之后:
<repositories>
<repository>
<id>jenkov.code</id>
<url>http://maven.jenkov.com/maven2/lib</url>
</repository>
</repositories>
11. Maven插件
使用Maven插件,可以向构建过程添加自定义的动作。创建一个简单的Java类,该类继承一个特殊的Maven类,然后为项目创建一个pom文件。该插件应该位于其项目下。
12.maven构建生命周期,阶段,目标
(1)生命周期
Maven有三个内嵌的生命周期:
-default
-clean
-site
这三个生命周期是互不干扰的,default是默认生命周期,负责项目的编译和打包;clean是删除target目录中之前生成的.class和.jar等文件,site关注的是为项目生成文档,实际上site可以为项目生成一个网页式的文档.
一个生命周期包含多个构建阶段,每个构建阶段又包括一系列目标.
(2)构建阶段
每一个构建生命期被分为一系列的构建阶段,构建阶段又被分为构建目标。因此,整个构建过程由一系列的构建生命期、构建阶段和构建目标组成。
你可以执行一个构建生命期,如clean或site,一个构建阶段,如default生命期的install,或者一个构建目标,如dependency:copy-dependencies。注意:你不能直接执行default生命期,你需要指定default生命期中的一个构建阶段或者构建目标。
当你执行一个构建阶段时,所有在该构建阶段之前的构建阶段(根据标准构建顺序)都会被执行。因此,执行install阶段,意味着所有位于install阶段前的构建阶段都会被执行,然后才执行install阶段。
default生命期更多的关注于构建代码。由于你不能直接执行default生命期,你需要执行其中一个构建阶段或者构建目标。default生命期包含了相当多的构建阶段和目标,这里不会所有都介绍。最常用的构建阶段有:
构建阶段 描述
validate 验证项目的正确性,以及所有必需的信息都是否都存在。同时也会确认项目的依赖是否都下载完毕。
compile 编译项目的源代码
test 选择合适的单元测试框架,对编译后的源码执行测试;这些测试不需要代码被打包或者部署。
package 将编译后的代码以可分配的形式打包,如Jar包。
install 将项目打包后安装到本地仓库,可以作为其它项目的本地依赖。
deploy 将最终的包复制到远程仓库,与其它开发者和项目共享。
将构建阶段的名称作为参数传给mvn命令,就是执行该构建阶段,如:
mvn package
该示例执行package构建阶段,因此在Maven的构建阶段序列中所有位于该阶段之前的阶段也都会被执行。
如果标准的Maven构建阶段和目标无法满足项目的需要,可以创建Maven插件增加你需要的构建功能。
(3)构建目标
构建目标是Maven构建过程中最细化的步骤。一个目标可以与一个或多个构建阶段绑定,也可以不绑定。如果一个目标没有与任何构建阶段绑定,你只能将该目标的名称作为参数传递给mvn命令来执行它。如果一个目标绑定到多个构建阶段,该目标在绑定的构建阶段执行的同时被执行.
13. 传递性依赖
传递性依赖是Maven2.0的新特性。假设你的项目依赖于一个库,而这个库又依赖于其他库。你不必自己去找出所有这些依赖,你只需要加上你直接依赖的库,Maven会隐式的把这些库间接依赖的库也加入到你的项目中。这个特性是靠解析从远程仓库中获取的依赖库的项目文件实现的。一般的,这些项目的所有依赖都会加入到项目中,或者从父项目继承,或者通过传递性依赖。
传递性依赖的嵌套深度没有任何限制,只是在出现循环依赖时会报错。
传递性依赖会导致包含库的依赖图增长的非常大。为了解决这个问题,Maven也提供了额外的机制,能让你指定哪些依赖会被包含:
依赖调解 – 当项目中出现多个版本构件依赖的情形,依赖调解决定最终应该使用哪个版本。目前,Maven 2.0只支持“短路径优先”原则,意思是项目会选择依赖关系树中路径最短的版本作为依赖。当然,你也可以在项目POM文件中显式指定使用哪个版本。值得注意的是,在Maven2.0.8及之前的版本中,当两个版本的依赖路径长度一致时,哪个依赖会被使用是不确定的。不过从Maven 2.0.9开始,POM中依赖声明的顺序决定了哪个版本会被使用,也叫作”第一声明原则”。
“短路径优先”意味着项目依赖关系树中路径最短的版本会被使用。例如,假设A、B、C之间的依赖关系是A->B->C->D(2.0)和A->E->(D1.0),那么D(1.0)会被使用,因为A通过E到D的路径更短。但如果你想要强制使用D(2.0),那你也可以在A中显式声明对D(2.0)的依赖。
依赖管理 – 在出现传递性依赖或者没有指定版本时,项目作者可以通过依赖管理直接指定模块版本。之前的章节说过,由于传递性依赖,尽管某个依赖没有被A直接指定,但也会被引入。相反的,A也可以将D加入<dependencyManagement>元素中,并在D可能被引用时决定D的版本号。
依赖范围 – 你可以指定只在当前编译范围内包含合适的依赖。
排除依赖 – 如果项目X依赖于项目Y,项目Y又依赖项目Z,项目X的所有者可以使用”exclusion”元素来显式排除项目Z。
可选依赖 – 如果项目Y依赖项目Z,项目Y的所有者可以使用”optional”元素来指定项目Z作为X的可选依赖。那么当项目X依赖项目Y时,X只依赖Y并不依赖Y的可选依赖Z。项目X的所有者也可以根据自己的意愿显式指定X对Z的依赖。(你可以把可选依赖理解为默认排除)。
下面对依赖范围进行详细说明.
依赖范围会影响传递性依赖,同时也会影响项目构建任务中使用的classpath。
Maven有以下6种依赖范围:
compile
这是默认范围。如果没有指定,就会使用该依赖范围。编译依赖对项目所有的classpath都可用。此外,编译依赖会传递到依赖的项目。
provided
和compile范围很类似,但provided范围表明你希望由JDK或者某个容器提供运行时依赖。例如,当使用Java EE构建一个web应用时,你会设置对Servlet API和相关的Java EE APIs的依赖范围为provided,因为web容器提供了运行时的依赖。provided依赖只对编译和测试classpath有效,并且不能传递。
runtime
runtime范围表明编译时不需要依赖,而只在运行时依赖。此依赖范围对运行和测试classpath有效,对编译classpath无效。
test
test范围表明使用此依赖范围的依赖,只在编译测试代码和运行测试的时候需要,应用的正常运行不需要此类依赖。
system
系统范围与provided类似,不过你必须显式指定一个本地系统路径的JAR,此类依赖应该一直有效,Maven也不会去仓库中寻找它。
import(Maven2.0.9及以上)
import范围只适用于pom文件中的<dependencyManagement>部分。表明指定的POM必须使用<dependencyManagement>部分的依赖。因为依赖已经被替换,所以使用import范围的依赖并不影响依赖传递。
Maven学习笔记