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.0
http://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.0
http://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包到本地仓库中。使用dependency的一个例子如下所示:
<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服务器),中心仓库.
8.外部依赖
有时只有一个jar包而没有它的groupId和artifactId,并且三种maven仓库中都没有这个jar包项目,但当前项目依赖这个jar包,这种依赖叫做外部依赖,可以用如下配置指定外部依赖。
<dependency>
<groupId>mydependency</groupId>
<artifactId>mydependency</artifactId>
<scope>system</scope>
<version>1.0</version>
<systemPath>${basedir}warWEB-INFlibmydependency.jar</systemPath>
</dependency>
这种方式需要在每一个maven工程的pom.xml中这么写,这样岂不是十分麻烦。一种解决方案是把第三方jar包安装到本地maven仓库中去。
mvn install:install-file -Dfile= -DgroupId= -DartifactId= -Dversion= -Dpackaging=
在这个命令中,需要手动提供groupId
,artifactId
等,(groupId,artifactId,version)三元组决定了一个jar包的坐标,groupId
是作者信息,artifactId
是作品名称,version是作品版本号,packaging是打包类型,可以取值war,jar等。如果第三方jar包有相应的pom.xml,则不必提供groupId
,artifactId
等信息,因为它们都在pom.xml里面进行了描述。可以使用如下命令:mvn install:install-file -Dfile= -DpomFile=
。
例如,如下命令安装com.oracle的ojdbc14。
mvn install:install-file -DgroupId=com.oracle -DartifactId=ojdbc14 -Dversion=10.2.0.1.0 -Dpackaging=jar -Dfile=ojdbc14.jar
在maven中进行如下配置
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc14</artifactId>
<version>10.2.0.1.0</version>
</dependency>
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:datajavaproductsmaven
epository
</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加入
依赖范围 – 你可以指定只在当前编译范围内包含合适的依赖。
排除依赖 – 如果项目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文件中的部分。表明指定的POM必须使用 部分的依赖。因为依赖已经被替换,所以使用import范围的依赖并不影响依赖传递。
14. 使用镜像中心仓库
用maven下载好慢啊,快试试阿里云镜像吧!修改$MAVEN_HOME/conf/settings.xml
<!-- 阿里云仓库 -->
<mirror>
<id>alimaven</id>
<mirrorOf>central</mirrorOf>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/repositories/central/</url>
</mirror>
在IntelliJ中,默认Maven配置从~/.m2/settings.xml中读取。虽然上面改对了,但是IDE不知道去哪里读取settings.xml,所以需要在Settings/Build Tools/Maven中进行设置。