开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第16天,点击查看活动详情
maven概念
Maven 是一个项目管理和整合工具。Maven 为开发者提供了一套完整的构建生命周期框架。开发团队几乎不用花多少时间就能够自动完成工程的基础构建配置,因为 Maven 使用了一个标准的目录结构和一个默认的构建生命周期。
在有多个开发团队环境的情况下,Maven 能够在很短的时间内使得每项工作都按照标准进行。因为大部分的工程配置操作都非常简单并且可复用,在创建报告、检查、构建和测试自动配置时,Maven 可以让开发者的工作变得更简单。
Maven 的主要目的是为开发者提供
-
一个可复用、可维护、更易理解的工程综合模型
-
与这个模型交互的插件或者工具
Maven 工程结构和内容被定义在一个 xml 文件中 - pom.xml
安装配置
windows安装
下载后解压,添加环境变量即ok
maven下载地址:http://maven.apache.org/download.html
linux安装
- 下载 maven 包
https://maven.apache.org/download.cgi
-
解压:
tar -zxvf apache-maven-3.8.6-bin.tar.gz -
配置环境变量:
vim /etc/profile
保存以后,重载环境变量: source /etc/profile
- 查看结果
mvn –v
- 配置maven文件
替换maven源为阿里云的: vim /tools/module/apache-maven-3.8.6/conf/settings.xml
指定下载资源位置
指定JDK版本
maven初体验
maven主要是做什么的?---打jar、war包和管理jar包
原始的javac打包
假如我们有一个Hello.java文件,想要将它打成可执行jar包,一般这样做。
使用javac命令和jar命令打包
生成的jar包文件,由两部分组成,class文件和META-INF目录,如下:
此时的jar包,是不可直接运行的,需要指定入口main类
进入META-INF目录,编辑MANIFEST.MF文件,如下:
运行此jar包,得到运行结果
maven打包
在pom文件内配置入口类
执行maven打包命令 mvn package ,最后运行生成的jar,结果与原始方式无区别
POM结构
maven流程
maven的理想
模板方法设计模式
- 自动走完标准的构建流程:清理->编译->测试->报告->打包->部署
- 统一入口,所有配置在一个pom里搞定
maven的约定
| src/main/java –存放项目的.java文件 |
|---|
| src/main/resources ---存放项目资源文件。比如spring,hibernate配置文件 |
| src/test/java ---存放全部測试.java文件,比方JUnit測试类 |
| src/test/resources ---测试资源文件 |
| target ---项目输出位置,编译完毕后的东西放到这里面 |
| pom.xml 在根目录下 |
maven的生命周期
maven的构建生命周期,只是一个抽象规范流程。周期内的每个阶段的具体执行,是在插件里来实现。
各个生命周期预设的定义如下:
| 阶段* | 处理* | 描述* |
|---|---|---|
| 验证 validate | 验证项目 | 验证项目是否正确且所有必须信息是可用的 |
| 编译 compile | 执行编译 | 源代码编译在此阶段完成 |
| 测试 Test | 测试 | 使用适当的单元测试框架(例如JUnit)运行测试。 |
| 包装 package | 打包 | 创建JAR/WAR包如在 pom.xml 中定义提及的包 |
| 检查 verify | 检查 | 对集成测试的结果进行检查,以保证质量达标 |
| 安装 install | 安装 | 安装打包的项目到本地仓库,以供其他项目使用 |
| 部署 deploy | 部署 | 拷贝最终的工程包到远程仓库中,以共享给其他开发人员和工程 |
运行任何一个阶段,都会从其所在生命周期的第一个阶段开始,顺序执行到指定的阶段,如:
mvn package --- 本义:执行default周期的package阶段,maven会自动从process-resources阶段开始运行到package阶段结束
maven的插件
插件plugin是绑定到生命周期,承担实际功能的组件。mvn运行时,自动关联插件来运行
下图是maven默认的各阶段对应的插件列表:
| 生命周期 | 生命周期阶段 | 插件目标 | 执行任务 |
|---|---|---|---|
| clean | pre-clean | ||
| clean | maven-clean-plugin:clean | 删除项目的输出目录。 | |
| post-clean | |||
| site | pre-site | ||
| site | maven-site-plugin:site | ||
| post-site | |||
| site-deploy | maven-site-plugin:deploy | ||
| default | process-resources | maven-resources-plugin:resources | 复制主资源文件至主输出目录 |
| compile | maven-compiler-plugin:compile | 编译主代码至主输出目录 | |
| process-test-resources | maven-resources-plugin:testResources | 复制测试资源文件至测试输出目 | |
| test-compile | maven-compiler-plugin:testCompile | 编译测试代码至测试输出目录 | |
| test | maven-surefire-plugin:test | 执行测试用例 | |
| package | maven-jar-plugin:jar(ejb:ejb jar:jar rar:rar war:war) | 创建项目jar包 | |
| install | maven-install-plugin:install | 将项目输出构件安装到本地仓库 | |
| deploy | maven-deploy-plugin:deploy | 将项目输出构件部署到远程仓库 |
常用Maven命令
mvn clean 清理
mvn compile 编译主程序
mvn package 打包
mvn install 安装jar到本地库
使用maven命令生成项目(idea和eclipse生成项目最终也是依赖maven插件生成的)
mvn archetype:generate -DgroupId=maventest -DartifactId=simple -DarchetypeArtifactId=maven-archetype-quickstart -Dversion=1.0
mvn archetype:generate -DgroupId=maventest -DartifactId=simple-web -DarchetypeArtifactId=maven-archetype-webapp -Dversion=1.0
maven插件开发
可以自定义插件,来扩展maven的功能。插件的开发步骤如下:
1、引入maven api的依赖
2、编写简单Mojo类---继承AbstractMojo
3、执行插件
mvn com.xx:xx-plugin:1.0:log
4、关联插件到生命周期来执行
构建项目对应的生命周期
maven坐标与依赖
坐标
在数学中, 任何一个坐标可以唯一确定一个 “点”
Maven 中坐标是Jar包的唯一标识
坐标元素包括groupId、artifactId、version、packaging:
| 元素 | 描述 | 说明 |
|---|---|---|
| groupId | 定义当前模块隶属的实际Maven项目 | 中小企业常常直接对应公司/组织 |
| artifactId | 定义实际项目中的一个Maven模块 | 唯一标识一个模块 |
| version | 定义当前项目所处版本 | SNAPSHOT 表示不稳定的版本。 LATEST 指最新发布的版本,可能是个发布版,也可能是一个snapshot版。 RELEASE 指最后一个发布版。 |
| packaging | 定义Maven项目打包方式 | 有jar(默认)、war、pom、maven-plugin等. |
| classifier | 附属构件(如javadoc、sources) | 须有附加插件的帮助 |
依赖
依赖即:A -->B,B-->C,C-->D这种项目间的依存关系。
在java的jvm内,依赖的最终表现是,项目A启动时,其依赖的jar包必须都对应放入其classpath路径内
依赖传递:
上述过程中,项目Mall归结起来,依赖的fastjson会有三个版本。
而我们的jvm最终肯定只能接受一个版本的jar,所以必须有所取舍
maven默认的取舍规则是:
1、路径最短原则:product和customer里的fastjson引用路径较短,路径为两步 ;pay项目里的fastjson引用路径较长,路径为三步。因此pay中的fastjson被淘汰
2、同路径长度下,谁先声明谁优先: product和customer中的fastjson路径相同,那么就看在pom中是先声明product还是先声明customer,谁先用谁的
依赖冲突及解决
在依赖传递里,我们看到,maven根据自己的规则为我们取舍出了一个版本的jar,但此jar版本选择可能会与我们的项目预期不符,
如:我们最终想的版本是fastjson:1.2.30版本-----但它在第一步即被淘汰掉了
当出现此类情况时,我们项目运行可能会出错(项目中使用到了1.2.30版本的特性)--------------- 此问题即是我们常遇到的jar包冲突问题
补救方式 ----- 使用exclusions将product和customer中的fastjson包排除掉,用法如下图:
当发生jar冲突程序报错时,可以使用mvn命令查出项目最终依赖的jar包树,看版本是否是我们预期的:
mvn dependency:tree
依赖范围scope
mvn在运行时,生命周期的不同阶段,会有不同的依赖范围,一般有以下依赖范围scope:
- compile :默认范围,用于编译 ------- 依赖的jar在打包时会包含进去
- provided:类似于编译,但支持你期待jdk或者容器提供,类似于classpath -------- 依赖的jar在打包时不会包含进去
- runtime: 在执行时需要使用 -------依赖的jar在打包时会包含进去
- test: 用于test任务时使用 -------依赖的jar在打包时不会包含进去
- system: 需要外在提供相应的元素。通过systemPath来取得 ----- 一般禁止使用
每个scope实际上是配置了一个不同的classpath,jvm根据选择不同的classpath来达到依赖不同
环境激活---profiles的使用
在springmvc项目中,开发/测试/线上三个不同环境,配置文件往往也不同。
打包时需要对配置文件做出选择---maven提供了profiles机制供我们使用
profiles的场景
这个选择,实际发生在default生命周期的resource阶段---maven-resources-plugin执行过程里
定义profiles
为了指导插件将对应的resource文件打入classpath里,先定出profiles
此定义即指,当mvn命令执行时,我们需要通过 -P dev或者-P test方式传入我们的意图:
dev/test选择,会导致properties里的变量值含义不同,我们主要关注 package.environment变量
资源插件的配置指定
配置maven-resources-plugin插件执行时,要复制的目录资源
mvn约定的资源中需要过滤掉环境目录
需要将mvn约定的资源目录里,过滤掉环境目录
小属性更轻便的用法
对于简单的属性,我们可以选择更轻便的用法
直接在环境中定义属性值
项目属性文件配置
约定的资源启用替换过滤
dependencyManagement使用
作版本号管理使用
1、dependencyManagement是声明而不引入依赖--------因此子项目需要显式的声明需要用的依赖(不需要版本号)
2、子项目中引用一个依赖而无版本号时,会沿着父子层次向上走,直到找到一个拥有dependencyManagement元素的项目,使用其版本号
用来实现多继承
1、maven只能单继承,即一个项目只能使用parent标签定一个父级项目
2、使用dependencyManagement并设置其scope=import,即表示继承此项目为父项目
maven版本
SNAPSHOT
SNAPSHOT---快照版本:以-SNAPSHOT为结尾的版本号(是一系列的版本的集合),随时更新不稳定的---每个版本都只是特定时间点的快照
例如:A-->B-1.3.8-SNAPSHOT(理解为A依赖了B的1.3.8-SNAPSHOT版本),那么B-1.3.8-SNAPSHOT更新之后重新deploy到仓库之后,A只 需要重新构建就可以拿到最新的代码,不用修改依赖B的版本。这样达到了变更传达的透明性。
SNAPSHOT的不稳定性,带来风险----本地仓库中快照版本的依赖的目录下会看到带有时间戳的jar包
RELEASE
RELEASE---发布(正式)版本:所有非-SNAPSHOT结尾的版本号,是稳定的版本号。---应该一旦发布永远不变。-----有的仓库会配置成redeploy覆盖(挖坑专家)
maven仓库
---------maven仓库,就是放置所有的jar文件的地方
本地仓库
本地环境安装maven后,会生成一个本地仓库位置(.m2/respository/ ),可在maven的配置文件中更改此位置(建议更改)
<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository>D:/mvn</localRepository>
</settings>
远程仓库和中央仓库
当maven要查找构件时,发现本地仓库中没有,则需要从远程仓库下载构件到本地仓库,供项目使用。
如下面,就使用阿里云仓库:
<mirrors>
<mirror> <id>alimaven</id>
<name>aliyun maven</name>
<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
当我们不配置远程仓库时,maven会默认一个仓库,即maven官方的仓库,称之中央仓库
URL:<http://search.maven.org/#browse>
Maven 依赖搜索顺序
当我们执行 Maven 构建命令时,Maven 开始按照以下顺序查找依赖的库:
依赖是具体的发布版本
· 步骤 1 - 在本地仓库中搜索,找到则成功。
· 步骤 2 - 在远程仓库中搜索,找到则下载。
· 步骤 3 - 如果没有设置远程仓库,Maven 默认去中央仓库搜索,找到则下载。
· 步骤 4 - 在一个或多个远程仓库中搜索依赖的文件,如果找到则下载到本地仓库以备将来引用,否则 Maven 将停止处理并抛出错误(无法找到依赖的文件)。
依赖是快照版本(RELEASE或LATEST)
步骤 1 - 基于更新策略更新(updatePolicy= always),则总是尝试去远程仓库拉取最新版本
步骤 2 - 强制快照更新------mvn clean install-U
主要参考 享学课堂peter老师