文章目录
- 1.Maven简介
- 1.1 传统项目管理状态分析
- 1.2 什么是maven
- 1.3 Maven的作用
- 2.maven的安装与配置
- (1)maven的下载与安装
- (2)Maven目录结构
- (3)配置settings.xml
- (4)maven整合idea
- (5)创建的maven工程
- 3.Maven相关基本概念
- 3.1 仓库
- 3.2坐标
- 3.3 镜像仓库
- 4.Maven的配置文件 pom.xml
- 5.依赖管理
- 5.1 依赖传递
- 5.2 解决依赖冲突的问题
- 5.2 依赖范围
- 6.Maven的生命周期(面试题)
- 7.插件
- (1)maven管理项目生命周期过程都是基于插件(jar)完成的
- (2)通过插件可以自定义其他功能(tomcat插件)
- (3)maven相关指令执行方式
- 8.Maven聚合与继承
- 8.1 Maven分模块开发
- 8.2 聚合与继承
- 8.2.1 聚合
- 8.2.2 继承
- 8.2.2 聚合和继承的关系
- 9. Maven常见问题的解决方案
- 9.1 在聚合工程中使用骨架创建子模块产生的问题
- 9.2 手动添加依赖
- 9.3 聚合工程中子模块引用其他子模块配置文件
1.Maven简介
1.1 传统项目管理状态分析
- 前面我们通过 Web 阶段项目,要能够将项目运行起来,就必须将该项目所依赖的一些 jar 包添加到 工程中,否则项目就不能运行。试想如果具有相同架构的项目有十个,那么我们就需要将这一份 jar 包复制到十个不同的工程中。我们一起来看一个 CRM项目的工程大小。 使用传统 Web 项目构建的 CRM 项目如下:
- 原因主要是因为上面的 WEB 程序要运行,我们必须将项目运行所需的 Jar 包复制到工程目录中,从而导致了工程很大。 同样的项目,如果我们使用 Maven 工程来构建,会发现总体上工程的大小会少很多。如下图:
- 此外还有一些其他的问题,比如jar包繁多,容易导致jar包版本不统一,引起jar包冲突的问题。
1.2 什么是maven
Maven 的正确发音是[ˈmevən]。Maven 在美国是一个口语化的词语,代表专家、内行的意思。 一个对 Maven 比较正式的定义是这么说的:Maven 是一个项目管理工具,它包含了一个项目对象模型 (POM:ProjectObject Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency ManagementSystem),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标 (goal)的逻辑。
-
一个项目对象模型 (Project Object Model)
一个maven工程都有一个pom.xml文件,用来定义项目的坐标、项目依赖、项目信息、插件目标等。 -
一组标准集合
(约定优于配置)
maven将整个项目管理过程定义一组标准(Maven项目有一个自己默认的配置,使用者不需要修改那些约定的内容,这就是 “约定优于配置”)- 比如:通过maven构建工程
有标准的目录结构
,有标准的生命周期阶段
、依赖管理有标准的坐标定义
等。 - 动态web的Maven项目的目录约定如下图所示
- 比如:通过maven构建工程
-
一个项目生命周期(Project Lifecycle)
使用maven完成项目的构建,项目构建包括:验证、清理、编译、测试、打包、安装、部署等过程。maven将这些过程规范称为一个生命周期。 -
一个依赖管理系统(Dependency Management System)
通过maven的依赖管理对项目所依赖的jar包进行统一管理。 -
插件(plugin)目标
maven管理项目生命周期过程都是基于插件(jar)完成的。
1.3 Maven的作用
- 自动下载需要的 jar 包,管理 jar 包的版本以及它们之间的依赖关系。
- 帮你编译程序
- 帮你打包程序(jar/war)
- 帮你部署程序
- 帮你管理项目中各个模块的关系
- 帮你自动运行单元测试
- 统一开发结构,提供标准、统一的项目结构
2.maven的安装与配置
(1)maven的下载与安装
-
下载
官网:http://maven.apache.org/
下载地址:http://maven.apache.org/download.cgi -
解压安装(下载zip文件)
- 注意不要安装在中文目录中
-
配置环境变量
- maven_home
- 在path变量中添加maven指令的目录
(2)Maven目录结构
-
bin: 存放了 maven 的命令,比如 mvn、tomcat:run
-
boot: 存放了一些 maven 本身的引导程序,如类加载器等
-
conf: 存放了 maven 的一些配置文件,如 setting.xml 文件
-
lib: 存放了 maven 本身运行所需的一些 jar 包 至此我们的 maven 软件就可以使用了,前提是你的电脑上之前已经安装并配置好了 JDK。
(3)配置settings.xml
-
本地仓库的目录配置
- 默认:maven的本地仓库是 /users/用户名/.m2/repository
<localRepository>D:\\java\\maven\\myrepository</localRepository>
-
镜像仓库配置(提高下载速度在
<mirrors>
标签中添加如下子标签)<!-- 阿里云仓库 --> <mirror> <id>alimaven</id> <mirrorOf>central</mirrorOf> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/repositories/central/</url> </mirror>
-
检验配置效果
- cmd -> mvn -v
(4)maven整合idea
- 以idea2021为例做全局配置,在idea的启动欢迎页
- 点击OK按钮,并关闭idea,再次打开idea,确认maven配置
(5)创建的maven工程
- maven项目目录结构及配置说明
- 创建maven项目(java/web)
3.Maven相关基本概念
3.1 仓库
- 本地仓库: 用来存储从远程仓库或中央仓库下载的插件和 jar 包,对于项目使用一些插件或 jar 包,manen项目优先从本地仓库查找
- 远程仓库(私服): 如果本地需要插件或者 jar 包,本地仓库没有,默认去远程仓库下载。远程仓库可以在互联网内也可以在局域网内。
- 可以是公司自定义开发的jar包(内部使用),可能需要使用VPN(离开公司的局域网后,就使用不了)
- 内网开发: 无法连接到外网,所依赖的jar需要先同步到本地私服里
- 每个公司会有对应的远程仓库(私服),我们到了公司去配置的话,直接去将公司提供的settings复制到本地maven里面(idea集成maven)
- 中央仓库: 在 maven 软件中内置一个远程仓库地址http://repo1.maven.org/maven2 ,它是中央仓库,服务于整个互联网,它是由 Maven 团队自己维护,里面存储了非常全的 jar 包,它包 含了世界上大部分流行的开源项目构件。
3.2坐标
- 什么是坐标?
- maven中的坐标用于描述仓库中资源的位置。
- https://mvnrepository.com/
- Maven坐标的主要构成
- groupId(分组): 定义当前maven项目隶属组织名称(通常是域名反写,例如org.mybatis)
- artifactId(模板id): 定义当前maven项目名称(通常是模块名称)
- version(版本号): 定义当前项目版本号
- packaging 定义该项目的打包方式(war/jar)
- Maven的作用
- 使用唯一标识,用来定位资源。通过该标识可以将资源的识别与下载交给机器完成
3.3 镜像仓库
解决中央仓库资源下载慢的问题!
- 在settings配置文件中,配置阿里云镜像仓库
<mirror>
<!-- mirror -->
<id>nexus-aliyun</id>
<!-- -->
<mirrorOf>central</mirrorOf>
<!-- -->
<name>Nexus aliyun</name>
<!-- URL -->
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>
4.Maven的配置文件 pom.xml
5.依赖管理
5.1 依赖传递
- 每一个依赖就是一个maven工程
- 依赖指的是当前项目运行所需要的jar,一个项目可以有很多个依赖。
- 依赖具有传递性:
- 直接依赖: 在当前项目中,通过依赖配置建立的依赖关系。
- 间接依赖: 被依赖的资源,如果还依赖其他资源,那么当前项目间接依赖其他资源。
5.2 解决依赖冲突的问题
- 依赖冲突是指项目依赖的某一个jar包,有多个不同的版本,因而造成类包版本冲突。
- 解决依赖冲突(四种方式)
- 版本依赖锁定(
重点
)
使用dependencyManagement 进行版本锁定,dependencyManagement可以统一管理项目的版本号,确保应用的各个项目的依赖和版本一致。
- 使用第一声明优先的原则
谁先定义的就用谁的传递依赖,即在pom.xml文件自上而下,先声明的jar坐标,就先引用该jar的传递依赖。 - 路径近优先原则—直接依赖高于间接依赖
即直接依赖级别高于传递依赖。 - 排除依赖原则
- 版本依赖锁定(
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.7.RELEASE</version>
<!-- 排除的依赖不需要添加依赖的版本号 -->
<exclusions>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
</exclusions>
</dependency>
5.2 依赖范围
(1)什么是依赖范围?
- 依赖的jar包在默认情况下可以在任何范围内使用,可以通过scope标签来控制其作用范围。
- 作用范围:
- 主程序范围有效(main文件夹)
- 测试程序范围有效(test文件夹)
- 是否参与打包(package指令范围之内)
(2)scope选取作用范围
-
test: 范围是指测试范围有效,在编译和打包时都不会使用这个依赖
-
compile: 范围是指编译范围内有效,在编译和打包时都会将依赖存储进去
-
provided: 依赖,在编译和测试过程中有效,最后生成的war包时不会加入 例如:servlet-api,因为servlet-api tomcat服务器已经存在了,如果再打包会冲突
-
runtime: 在运行时候依赖,在编译时候不依赖
-
默认是compile
6.Maven的生命周期(面试题)
- Maven对项目周期的构建分为三个阶段
- clean: 清理工作阶段。 移除所有上一次构建生成的文件(.class文件和对应的报告)
- default: 核心工作阶段。比如编译、测试、打包、安装、部署等
- site: 产生报告,发布站点等
- clean生命周期
- pre-clean 执行一些需要在clean之前完成的工作
- clean 移除所有上一次构建生成的文件
- post-clean 执行一些需要在clean之后立刻完成的工作
default生命周期
- validate (校验) :校验项目是否正确并且所有必要的信息是否可以完成项目的构建过程。
compile (编译)
:编译项目的源代码。test (测试)
: 使用合适的单元测试框架运行测试(Juint是其中之一)package (打包)
:将编译后的代码打包成可分发格式的文件,比如jar、war- verify (验证) : 运行任意的检查来验证项目包有效且达到质量标准。
install (安装)
: 将当前项目包安装到本地maven库,供其他项目依赖deploy (部署)
:将最终的项目包复制到远程仓库中与其他开发者和项目共享。- 执行后面的命令会自动执行前面的命令,比如执行mvn package时会执行validate、clean、compile、test、package五个阶段。
- site生命周期
- pre-site 执行一些需要在生成站点文档之前完成的工作
- site 生成项目的站点文档
- post-site 执行一些需要在生成站点文档之后完成的工作,并且为部署做准备
- site-deploy 将生成的站点文档部署到特定的服务器
7.插件
- maven管理项目生命周期过程都是基于插件(jar)完成的
- 插件与生命周期内的阶段绑定,在执行到对应生命周期时,执行对应的插件功能
- 通过插件可以自定义其他功能(tomcat插件)
(1)maven管理项目生命周期过程都是基于插件(jar)完成的
- mvn compile
- mvn clean
- mvn test
(2)通过插件可以自定义其他功能(tomcat插件)
- 在
<build>
下新建<plugins>
如下代码
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<!-- 自定义tomcat服务器的端口-->
<port>8088</port>
<!-- 项目发布后的应用目录-->
<path>/</path>
</configuration>
</plugin>
</plugins>
(3)maven相关指令执行方式
- 方式一:命令行
- 方式二:maven面板(双击执行)
方式三:配置Edit Configurations
8.Maven聚合与继承
8.1 Maven分模块开发
- 将一个项目的不同包转化为对应的一个maven工程,将所有的子工程放在一个父工程中
8.2 聚合与继承
8.2.1 聚合
(1)思考一个问题:
- 上面的各个模块是分开独立开发的,彼此互相独立,互补影响。假设如果现在maven-dao模块更新升级了,那么其他模块是如何感知dao模块发生了变化的?
(2)解决方案(聚合工程):
- 创建一个父工程,专门对这些模块进行管理。对这些模块进行统一的编译,测试,打包等操作。一旦一个模块发生了变化,会同时对其他模块也进行编译、测试、打包。
(3)聚合工程 :指多个模块的集合,通过父工程进行统一管理
- 聚合的作用:
- 用于快速构建maven工程,一次性管理多个模块。
-所有的子工程它们的生命周期和父工程是一致的,父工程可以全局管理所有的子工程
(4)聚合工程的创建过程
- 创建一个maven工程,定义打包方式为pom(作为父工程,不包含src文件夹)
<groupId>com.qfedu</groupId>
<artifactId>day03-museum-parent</artifactId>
<!-- 父工程打包方式-->
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
- 定义当前父工程管理的其他模块的名称(父工程聚合其他子模块)
<modules>
<module>museum-utils</module>
<module>museum-entity</module>
<module>museum-vo</module>
<module>museum-mapper</module>
<module>museum-service</module>
<module>museum-filter</module>
<module>museum-controller</module>
</modules>
- 测试父工程通过生命周期管理子工程
- eg: mvn compile
- 此时所有的模块都会进行编译。
- 问题:编译的顺序是怎么样的?
- 参与聚合操作的模块最终执行顺序与模块的依赖关系有关系。跟配置顺序没有关系。
(5)各个模块的打包方式
- 父工程打pom
- Web工程打war包
- 其他工程 打jar包(如果没有任何打包配置,默认就是打jar包)
8.2.2 继承
(1)继承的作用与实现
- 作用:通过继承可以实现在父工程中的配置,让子模块沿用。类似于java中的继承关系。
- 比如在父工程中引入依赖与插件,子模块也会含有父工程中引入依赖与插件(子模块从父工程继承过来的)
- 继承关系实现:
- 在子模块中,使用parent标签引入父工程,这样子工程和父工程就有了继承关系了
- 在子模块中,使用parent标签引入父工程,这样子工程和父工程就有了继承关系了
(2)继承产生的问题与解决办法
- 继承产生的问题
- 并不是子模块都需要所有父工程的资源。 以maven-dao为例,这个子模块并不需要tomcat插件,也不需要servletjsp相关的依赖。如果全部资源都继承下来会导致子模块特别大,将来打包,部署效率比较低。
- 解决办法
- 在父工程中的pom.xml中使用
<dependencyManagement>
标签帮我们管理依赖(只会进行版本锁定,不会导入依赖) - 在子模块中按照自己的需求,引入对应的依赖,此时不需要加依赖的版本号了,因为在父工程里面已经给我们定义好了(但是需要添加
<scope>
指定依赖的作用范围)- 注: 若在子模块中也引入了版本号,则子模块会使用自身指定的版本号,不会使用父工程版本锁定的版本号
- 相同方式,在父工程中的pom.xml中使用
<pluginManagement>
标签帮我们管理插件(只会进行版本锁定,不会导入插件)
- 在父工程中的pom.xml中使用
8.2.2 聚合和继承的关系
-
作用:
- 聚合用于快速构建项目
- 继承用于快速配置项目
-
相同点:
- 聚合与继承的pom.xml文件打包方式均为pom。可以将两种关系定义在同一个pom文件中。
(通常使用maven实现聚合工程时(不使用骨架),其父工程既实现了与子模块的聚合也实现了与子模块的继承)
- 聚合和继承均属于设计系模块(应当手动删除src文件夹),并无实际的模块内容
- 聚合与继承的pom.xml文件打包方式均为pom。可以将两种关系定义在同一个pom文件中。
-
不同点
- 聚合是在当前模块中配置关系,聚合可以感知到参与聚合的模块都有哪些
- 继承是在子模块中配置关系,父模块无法感知哪些子模块继承了自己
9. Maven常见问题的解决方案
9.1 在聚合工程中使用骨架创建子模块产生的问题
- 问题:
- 通常使用maven实现聚合工程时,其父工程既实现了与子模块的聚合也实现了与子模块的继承,但是若在创建子模块时使用
maven骨架创建
则父工程与子模块只包含聚合关系,不包含继承关系
- 通常使用maven实现聚合工程时,其父工程既实现了与子模块的聚合也实现了与子模块的继承,但是若在创建子模块时使用
- 原因:
- 使用webapp子模板在maven项目创建完后,会自动部署自己的模板,包括pom.xml,web.xml,index.jsp等文件,就会把maven子项目默认生成的pom.xml(含有 正确的parent)给覆盖掉
- 示例: 使用maven的webapp骨架创建子模块
- 在使用webapp骨架创建子模块时,刚开始其pom文件会包含
<parent>
标签,但在项目创建完成后,其pom文件中不在含有<parent>
标签,若想实现子模块与父工程的继承关系
需要手动添加<parent>
标签,引入父工程
- 在使用webapp骨架创建子模块时,刚开始其pom文件会包含
9.2 手动添加依赖
- 问题: 在某个
web子模块中
pom.xml文件中引入依赖不成功,如何手动添加jar包? - 解决方案:
-
在web子模块中的
src/main/webapp/WEB-INF
中创建lib
文件夹,将需要的jar包
导入- 原因: web项目最终打包为
war包
,其目录结构如下:
- 原因: web项目最终打包为
-
web项目打包为war包后 所有的依赖jar包最后都会在
WEB-INF
目录下,由于maven项目的约定大于配置
,可以直接在字模块的src/main/webapp/WEB-INF
中创建lib
文件夹,将需要的jar包
导入,最终生成的war
也会在其内部的WEB-INF
目录下包含手动创建lib
文件夹导入的jar包
-
9.3 聚合工程中子模块引用其他子模块配置文件
- 在Maven的聚合工程中,在某一个子模块的代码文件中可以直接引用其他子模块src/main/resources中的配置文件,无需做其它额外操作
- eg: 在utils子模块的某个java代码中,直接引用mapper子模块下src/main/resources的mybatis-config.xml配置文件