目录
(6.4)远程仓库:【中央仓库】,【私服】,【其他公开的远程仓库】
(6.5)如何配置【远程仓库】:在pom.xml中添加 标签
(6.6)如何验证【远程仓库】:settings.xml中配置 标签
(6.7)如何把本地项目部署到【远程仓库】:pom.xml文件配置和标签
(6.8)如何配置镜像:settings.xml中配置标签,代替某些的url
第一章:Maven简介
(1.1)何为Maven
- 构建工具,依赖管理工具,项目信息管理工具
- 提供免费的中央仓库
- 约定优于配置
(1.2)其他构建工具
- IDE:如Eclipse,Idea
- Make:最早的构建工具,Makefile的语法
- Ant:Another Neat Tool(另一个整洁的工具),最早用来构建Tomcat。与Maven类似,但是不提供依赖管理
第二章:Maven的安装和配置
(2.1)安装和配置
- 略
(2.2)配置文件
- $M2_HOME/conf/settings.xml
- 全局范围的,整台机器的所有用户都会受到该配置的影响
- ~/.m2/settings.xml
- 推荐使用!!!
- 用户级别的,不影响其他用户
- 升级Maven不需要重新配置
(2.3)Maven的文件目录
- bin:包含mvn的运行脚本,对于win来说,是.bat文件
- boot:只包含一个jar文件,Maven使用其加载自己的类库,对用户来说,不用关心该文件
- conf:包含非常重要的settings.xml文件。一般情况下更倾向于复制到~/.m2/目录下,在用户范围内定制Maven的行为
- lib:包含Maven运行时需要的Java类库,以及Maven内置的超级POM
第三章:Maven使用入门
(3.1)生命周期
- mvn clean:清理 target/
- mvn compile:编译项目主代码,到 target/classes 目录
- mvn test:
- mvn package:打包,如果POM中没有指定,默认打jar包,位于target/目录中
- mvn install:将jar包安装到本地repository
(3.2)如何生成可执行jar包
- 默认打包生成的jar包是不能直接运行的,为了生成可执行的jar包,需要用到 maven-shade-plugin 插件
(3.3)项目骨架
- Maven中的pom.xml对应于Make中的Makefile,Ant中的build.xml。
- Maven项目的一些约定:src/main/java 目录下放置项目的主代码,src/test/java 目录下放置项目的测试代码,这些基本目录结构和pom.xml被称为项目的骨架
- 快速创建项目骨架
- 首先执行命令:mvn archetype:generate
- 接着按提示输入:groupId, artifactId, version, package
第五章:坐标和依赖
(5.1)Maven的坐标
- groupId(必须定义):不关键,比如com.dianping.zebra,或者 com.sankuai.meituan
- artifactId必须定义:项目中的一个模块,推荐用模块名,比如xy-trade-microloan-thrift-api,或者 zebra-client
- version(必须定义):版本,比如 2.9.2-SNAPSHOT
- packaging(可选定义):定义了maven的打包方式,不定义packaging时默认jar包,当然也可以定义war包
- scope(可选定义):作用范围,默认为compile。如果<scope>test</scope>,表示只能在测试代码中import该依赖,主代码依赖会报错
- classifier(不能直接定义):定义一些附属组件,比如【javadoc文档】和【sources源代码】
(5.2)Maven依赖
<dependencies>
<dependency>
<groupId>com.dianping.zebra</groupId>
<artifactId>zebra-client</artifactId>
<version>2.9.2-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.2</version>
<scope>test</scope>
</dependency>
<dependencies>
- <groupId>,<artifactId>,<version>:依赖的基本坐标,Maven需要根据坐标才能找到依赖
- <type>(可选,默认为jar):依赖的类型,大多数情况下不必声明,默认为jar
- <scope>:依赖范围,见(3)
- <optional>:标记依赖是否可选,见(5)
- <exclusions>:排除传递性依赖,见(6)
(5.3)<scope>:依赖范围
- 概述:用来控制依赖与这三种classpath(编译,测试,运行)的关系,有以下几种选择
- compile(默认):在【编译,测试,运行】时都使用该依赖。比如spring-core(都需要用到)
- test:只对【test文件夹下】有效,在编译主代码或者运行项目时无法使用此类依赖。比如JUnit,mockito(只有在单元测试才用到这些依赖)
- provided:已提供该依赖。对于【编译和测试】有效。在运行时无效。
- runtime:对【测试和运行】有效,编译主代码时无效。典型的例子是JDBC驱动实现
- system:类似provided,但是provided可以通过本地maven仓库解析,system往往与本机系统绑定
- import:导入依赖范围,后面解释dependencyManagement时再介绍
(5.4)Maven的传递性依赖性质
- 何为依赖传递:【我的项目A】依赖【spring-core】,【spring-core】pom.xml中依赖【commons-logging】。则 【我的项目A】依赖【commons-logging】
- 依赖传递的范围:【我的项目A】依赖scope=test【spring-core】,【spring-core】依赖scope=compile【commons-logging】。则【我的项目A】依赖scope=test【commons-logging】
- 依赖的规则:第一原则优先,相同则采用第二原则
- 第一原则:依赖路径越短越优先。比如:A->B->C->X(1.0);A->D->X(2.0)。由于X(2.0)的路径短,X(2.0)会被解析使用
- 第二原则:看pom.xml中的依赖顺序,谁写在上面谁先依赖。比如A->B->Y(1.0);A->C->Y(2.0)。如果pom.xml文件中B写在C的上面,则Y(1.0)会被解析使用
(5.5)<optional>:可选依赖
- 配置 <optional> true </optional> ,则该依赖为【可选依赖】
- 【可选依赖】有什么用:不具有传递性
- 比如:A->B,B->mysql.jar(可选),B->oracle.jar(可选)。
- 则依赖不会传递,即 A不会依赖mysql.jar和oracle.jar。换句话说:项目里没有mysql.jar和oracle.jar不会对A产生任何影响
- 为什么要【可选依赖】
- 假如项目B实现了两个特性,其中的特性一依赖于X,特性二依赖于Y,而且这两个特性是互斥的,用户不可能同时使用这两个特性
- 比如B是一个持久层隔离工具包,特性一用于mysql,特性二用于oracle,这两者是互斥的,究竟用哪个,让用户自己来手动选(手动引入)
- 例子:B的pom.xml(图一),用户如果要用mysql的jar包,需要在A中自己手动引(下图)
-
图一:
-
图二:
-
(5.6)<exclusion>:排除依赖
- 假如项目里有个第三方依赖,该依赖还依赖了另一个1.0.0-SNAPSHOT版本的库,那么该1.0.0-SNAPSHOT就会成为当前项目的传递性依赖。此时我想排除该依赖,则要使用<exclusion>标签
- 需要注意的是:声明exclusion时候只需要groupId和artifactId,不需要version(显然,根据前两者就可以在pom.xml中唯一确定一个Maven坐标了)
(5.7)<properties>:归类依赖
- 假如项目里有很多Spring Framework的依赖(如下),你希望保持它们版本号一致,并且统一管理它们的版本
- org.springframework:spring-core:2.5.6
- org.springframework:spring-beans:2.5.6
- org.springframework:spring-context:2.5.6
- org.springframework:spring-context-support:2.5.6
- 使用<properties>标签
-
(5.8)优化依赖
- 可以通过命令查看项目中的所有依赖和依赖关系
- 显示所有已解析依赖:mvn dependency:list
- 查看解析后的依赖树:mvn dependency:tree
- 分析当前的项目依赖:mvn dependency:analyze
第六章:仓库
(6.1)Maven仓库和布局
- 何为仓库:Maven将所有【构建完成的jar包】安装部署到【Maven本地仓库】,防止浪费磁盘空间,并供各个项目调用
- Maven中【jar包路径】和【坐标】的关系:groupId/artifactId/version/artifactId-version.packaging,例子如下
(6.2)仓库的分类
- 只分为两类:【本地仓库】和【远程仓库】,一个用户只有一个【本地仓库】,但是可以配置多个【远程仓库】
- jar查找规则
- (1)先从【本地仓库】找
- (2)找不到再去【远程仓库】下载到【本地仓库】
- (3)如果都没有则报错
(6.3)本地仓库
- 默认配置下,【本地仓库】的路径为:用户目录/.m2/repository/...
- 比如Windows:C:\Users\jyy\.m2\repository\
- 如何更改【本地仓库】地址
- 将 $M2_HOME/conf/settings.xml 文件复制到 ~/.m2/settings.xml,并增加一行<localRepository> 标签配置。不过不推荐这个方式,因为不推荐修改全局目录的settings.xml文件
- 如何安装【本地Maven项目】到【本地仓库】
- 命令:mvn clean install
(6.4)远程仓库:【中央仓库】,【私服】,【其他公开的远程仓库】
- 【Maven中央仓库】:【Maven】自带的远程仓库,包含了绝大部分开源的构件:https://mvnrepository.com/
- Maven的安装文件自带【中央仓库】的配置,可以通过 $M2_HOME/lib/maven-model-builder-3.0.jar中的 org/apache/maven/model/pom-4.0.0.xml看到,该pom文件是一个超级POM,所有Maven项目都会继承
- 私服:架设在局域网内,代理外部广域网上的远程仓库
- jar包查询规则:先找【本地仓库】,再找【私服】,找不到再找【远程仓库】
- 为什么需要私服:
- 有些jar包是公司内部用的,不开源,可以放在私服
- 如果Internet不稳定,私服提高了稳定性
- 比较著名的有:Nexus
- 其他公开的远程仓库
- 常见的有 Java.net Maven库,JBoss Maven库
(6.5)如何配置【远程仓库】:在pom.xml中添加 <repositories> 标签
- <id>:必须是唯一的,Maven自带的中央仓库使用的id为central,如果其他仓库id声明也使用central,则会覆盖中央仓库的配置
- <name>:名称,随便去取
- <url>:仓库地址,一般是http协议格式,可以在浏览器中打开
- <releases>和<snapshots>标签
- <enabled>
- snapshots的<enabled>为false,表示不允许从 JBoss仓库下载【快照版本】的jar包
- releases 的 <enabled>为true,表示可以从 JBoss仓库下载【发布版本】的jar包
- <updatePolicy>:从Maven远程仓库检查更新的频率,3种选择
- never(从不检查更新)
- always(每次都检查)
- X(每隔X分钟检查一次)
- <checksumPolicy>:检查策略,3种选择
- warn(出错则输出warn警告)
- fail(出错则构建失败)
- ignore(完全忽略检验失败)
- 例子:
- <enabled>
- <layout>:default表示仓库的布局是Maven2和Maven3的默认布局
(6.6)如何验证【远程仓库】:settings.xml中配置 <servers> 标签
- 有时候,远程仓库只有部分人员能访问,需要配置用户名和密码才能访问,需要在Maven的settings.xml中配置
- 需要注意的是,<id>必须与前面pom.xml中<repository>的id相同
(6.7)如何把本地项目部署到【远程仓库】:pom.xml文件配置<repository>和<snapshotRepository>标签
<distributionManagement>
<repository>
<id>myCompany-nexus-releases</id>
<name>myCompany Nexus Repository</name>
<url>http://xxx.xxxxxxx.com/repository/releases</url>
</repository>
<snapshotRepository>
<id>myCompany-nexus-snapshots</id>
<name>myCompany Nexus Repository</name>
<url>http://xxx.xxxxxxx.com/repository/snapshots</url>
</snapshotRepository>
</distributionManagement>
- <project>中的<distributionManagement>标签
- <repository>表示:releases版本的仓库地址
- <snapshotRepository>表示:snapshots版本的仓库地址
- <id>标签必须要与 settings.xml中的id一致
- 需要注意的是,如果如果该repository需要用户名密码的话,需要配合(5)中的<servers>标签使用
- 配置好之后:mvn clean deploy命令会自动部署到远程仓库
(6.8)如何配置镜像:settings.xml中配置<mirror>标签,代替某些<repository>的url
- 何为镜像:就比如,阿里云提供了Maven仓库的国内镜像,国内用户下载起来会更快(https://maven.aliyun.com/repository/public)
- 例1:下图的<mirrorOf>为central,表示用该url替代了【Maven中央仓库】,所有去中央仓库的请求都会转到该url
- 例2:下图的<mirrorOf>为*,表示用该url替代了所有<repository>的配置,所有配置的<repository>都会转到该url镜像
- 如果该镜像需要认证,则去settings.xml中配置<server>即可
- <mirrorOf>的用法
- <mirrorOf> * </mirrorOf>:匹配所有远程仓库
- <mirrorOf> external:* </mirrorOf>:匹配所有远程仓库,但是 locolhost 和 file://协议的除外,即匹配所有不在本机上的远程仓库
- <mirrorOf> repo1, repo2 </mirrorOf>:匹配 repo1 和 repo2
- <mirrorOf> *, !repo1 </mirrorOf>:匹配所有远程仓库, repo1除外(感叹号表示排除)
(6.9)快照版本
- 为何需要snapshot版本
(6.10)仓库搜索服务
- 推荐几个强大的公共Maven仓库
- Sonatype Nexus:Nexus是目前最流行的开源Maven仓库管理平台,可以用它架设私服
- Javaana
- MVNbrowser
- MVNrepository
第七章:声明周期和插件
(7.1)三套生命周期
- Maven拥有3套相互独立的生命周期:分别是 clean(清理项目),default(构建项目),site(建立项目站点)
- clean生命周期:主要用于清理项目
- 1.1)pre-clean:执行清理前需要完成的工作
- 1.2)clean:清理上一次构建生成的文件
- 1.3)post-clean:执行清理后需要完成的工作
- default声明周期:三套生命周期中最核心的部分
- 验证和初始化
- 2.1)validate
- 2.2)initialize
- src/main/resources 处理和编译
- 2.3)generate-sources
- 2.4)process-sources:处理项目的主资源文件:一般来说,对src/main/resources 目录的内容进行变量替换等工作,复制到项目输出的主classpath目录中
- 2.5)generate-resources
- 2.6)process-resources
- 2.7)compile:编译项目的主源码:一般来说,是编译 src/main/java 目录下的Java文件至项目输出的主classpath目录中
- 2.8)process-classes
- src/test/resources 处理和编译
- 2.9)generate-test-sources
- 2.10)process-test-sources:处理项目的测试资源文件:一般来说,对src/test/resources 目录的内容进行变量替换等工作,复制到项目输出的测试classpath目录中
- 2.11)generate-test-resources
- 2.12)process-test-resources
- 2.13)test-compile:编译项目的测试源码:一般来说,是编译 src/test/java 目录下的Java文件至项目输出的测试classpath目录中
- 2.14)process-test-classes
- 运行测试代码
- 2.15)test:使用单元测试框架进行测试,测试代码不会被打包或者部署
- 打包,安装,部署
- 2.16)prepare-package
- 2.17)package:接受编译好的代码,打包可发布的格式,比如jar
- 2.18)pre-integration-test
- 2.19)integration-test
- 2.20)post-integration-test
- 2.21)verify
- 2.22)install:将包安装到Maven本地仓库,供本地其他Maven项目使用
- 2.23)deploy:将包部署到远程仓库
- 验证和初始化
- site声明周期:主要目的是建立和发布项目站点
- pre-site
- site
- post-site
- site-deploy:将生成的项目站点发布到服务器上
(7.2)Maven插件
- Maven的核心仅仅是定义了生命周期,具体的任务由插件完成。如maven-dependency-plugin
- 在repository/org/apache/maven/plugins目录下,可以看到一些下载好的插件
- 什么是插件目标
- compiler:compile(maven-compiler-plugin的compile目标)
- surefire:test(maven-surefire-plugin的test目标)
- 插件绑定
- 为了让用户不需要配置就能构建Maven项目,Maven在其主要生命周期绑定了很多插件的目标
- 自定义插件
- 如果有这样一个需求:创建项目的【源码jar包】
- maven-source-plugin可以完成该需求,需要在pom文件中自行配置
- <exclusions>下每个<exclusion>子元素可以用来配置执行一个任务
- <id>:该例中配置了一个id=attach-sources的任务
- <phase>:通过phase配置,将其绑定到verify生命周期阶段上
- <goal>:指定要执行的插件目标
- 可选:jar(对源码进行打包),jar-test(对test中的测试代码进行打包)
- 运行 mvn verify 会看到以下输出:表示 maven-source-plugin:jar-no-fork 得以执行
- 例子:
- 这个插件表示:在生命周期中的generate-test-resources阶段,将代码打成jar包
- 插件配置参数
- (1)命令行配置(常用)
- 常见形式:使用-D参数,伴随 key=value 形式
- mvn install -Dmaven.test.skip=true
- 常见形式:使用-D参数,伴随 key=value 形式
- (2)pom.xml中全局配置
- 比如,配置compile时生成java1.5的字节码文件
- (1)命令行配置(常用)
第八章:聚合与继承
(8.1)聚合:<module>标签
- 比如:存在两个同级的子模块,可以用一个【主pom.xml】管理多个【子pom.xml】
- 例1:
- 例2:来自zebra项目的主pom文件
-
<?xml version="1.0" encoding="UTF-8"?> <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/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.dianping.zebra</groupId> <artifactId>zebra-all</artifactId> <packaging>pom</packaging> <version>2.9.1</version> <name>zebra-all</name> <organization> <name>Meituan Dianping</name> <url>http://www.dianping.com/</url> </organization> <modules> <module>zebra-dao</module> <module>zebra-sample</module> <module>zebra-admin-web</module> <module>zebra-cat-client</module> <module>zebra-client</module> </modules> <description>zebra</description>
-
- 需要用到的标签
- <packaging>:主pom文件必须声明为pom,否则无法构建(但子pom文件可以不声明packaging,因为默认为jar)
- <module>:内容为【子pom文件】中的<artifactId> ,即子项目名称
- 父模块与子模块的结构
- (1)父子结构:最常用的目录结构
-
- (2)平行结构:不太常用,【父pom】中<moudle>中的路径需要变化
-
- (1)父子结构:最常用的目录结构
(8.2)继承:<parent>标签
- 为什么要聚合与继承:在所有子模块的【子pom】中,往往会写重复的依赖配置,比如spring-core, spring-beans等等
- 【子pom】如何继承【父pom】:<parent>标签
- 需要注意的是:一般采用【父子目录结构】无需声明<relativePath>,<relativePath>默认值是 ../pom.xml
- 这里的例子中没有为 account-email 声明 groupId 和 version,则默认采用父pom的。如果子模块需要和父模块不一样,则需要显示声明。
- 子模块的<artifactId>应该显示声明,因为它肯定得与父模块不一样
- 哪些标签可以被继承
(8.3)父子pom的依赖管理:<dependencyManagement>
- <dependencyManagement>能让子模块继承到父模块的依赖配置,但<dependencyManagement>的依赖声明不会引入实际的依赖
- 父模块的pom.xml:
- 子模块的pom.xml:
-
-
- 如上所示:<dependencyManagement>不会给【父模块】和【子模块】引入依赖,不过这段配置是会被继承的
- dependencyManagement中的依赖版本会覆盖传递依赖版本
- 举个例子:项目中依赖的A,A依赖了B的1.0版本。如果在dependencyManagement中显示声明依赖B的2.0版本,那么A也会去依赖B的2.0版本
- 对于子模块
- 如果需要依赖:只需要配置groupId和artifactId。而version不需要写,只需要委托给父类管理就行了
- 如果不需要依赖:在子pom.xml中不写就行了,不写就不会引入
(8.4)超级pom
- 超级pom的坐标:对于Maven3,超级pom的目录为:maven/lib/maven-model-builder-x.x.x.jar中
-
- 超级pom中定义了什么?
- (1)定义了【默认中央仓库】和【插件仓库】
- (2)定义了【主代码/测试 输出目录】,【主代码输出目录】,【最终构件的名称格式】等等
-
- (3)定义了【Maven内置插件】的默认版本
- (1)定义了【默认中央仓库】和【插件仓库】
(8.5)约定优于配置
- Maven提倡约定优于配置(Convention Over Configuration):在maven中只需要简单的配置pom文件,就可以实现 清除构建目录、创建目录、编译代码、复制依赖至目标目录,最后打包
- maven约定如下
- 源码目录为 src/main/java
- 编译输出目录为 target/classes
- 打包方式为jar
- 包输出目录为 target
(8.6)反应堆(Reactor)
- 什么是反应堆:在【父模块】构建项目时,各个【子模块】的构建顺序
- 构建顺序:并非按照<modules>中的顺序构建,而是根据依赖关系构建
- 例子
- account-aggregator模块中pom.xml中的定义顺序
- 依赖关系,都依赖parent
- 在account-aggregator项目下mvn clean install得到的真实构建顺序
- 先构建【父模块account-parent】,再根据依赖关系自上而下构建【子模块account-email】和【子模块account-persist】
- account-aggregator模块中pom.xml中的定义顺序
- 需要注意的是:模块间的依赖关系将反应堆构成一个【有向非循环图】,如果存在循环依赖,Maven会报错
- 如何裁剪反应堆:即如何【自定义构建】
- (1)不加参数,默认全部构建:mvn clean install
- (2)参数-pl,构建某些子模块(按逗号分割):mvn clean install -pl account-email,account-persist
- 如下所示,可以看到只有指定模块【account-email】和【account-persist】 被构建
- (3)参数-am,构建某些子模块以及【子模块所依赖的模块】:mvn clean install -pl account-email -am
- 如下所示,由于 account-email 依赖 account-parent,所以两者都被构建了
- (4)参数-amd,构建某些子模块以及【依赖该子模块的模块】:mvn clean install -pl account-parent -amd
- 由于 account-parent 被 account-email 和 account-persist 依赖,所以三个都被构建
其他
(10.1)maven统一配置资源属性值
- 需求:jdbc.url这些常用的配置,也用maven作统一管理
- 方案:
- (1)在pom.xml中的<properties>中自定义属性
- (2)在pom.xml中的<build>中添加如下的配置,指定某一moudle下的resources文件夹
- (3)更常用的写法,在(2)中只能指定某个moudle下的resources文件夹。改成如下格式后,针对每个moudle下的resources文件夹,都能起作用
- (4)如果想针对test下再做配置,maven也提供了相关标签<testResources>
- (1)在pom.xml中的<properties>中自定义属性
(10.2)跳过测试
- 方法一:
- 方法二:-DskipTests 命令参数