什么是maven
- Maven是一个项目管理工具,它包含了一个项目对象模型(POM, Project Object Model)、一组标准集合、一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System)和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑
- 两大核心功能:依赖管理和一键构建
maven工程标准目录结构
- src/main/java目录: 核心代码位置
- src/main/resources目录: 配置文件部分
- src/test/java目录: 测试代码部分
- src/test/resources目录:测试配置文件
- maven项目工程还多一个目录:src/main/webapp目录: 存放页面资源如:js、css、图片等
maven的仓库类型
- 1.本地仓库
- 2.远程仓库
- 1.maven中央仓库(地址:http://repo2.maven.org/maven2/)
- 2.maven私服
- 3.其他公共远程仓库(例如apache提供的远程仓库,地址:http://repo.maven.apache.org/maven2/)
maven常用命令
- 1.clean:清除target目录,清除之前的编译信息
- 2.compile:编译src/main下的代码,生成class文件并放置在target中
- 3.test:编译src/test和src/main下的代码,生成class文件并放置在target中
- 4.package:将项目打包,同时将src/main和src/test下边的代码同时进行编译
- 如果我们在pom.xml中指定<packing>war</packing>,则会打成war包;默认会打成jar包
- 5.install:安装,将当前开发的maven项目打包(packing)并安装到本地,在本地仓库中可以找到
- 6.deploy:发布,在此之前必须要进行一些配置
- 2-6为默认生命周期:如果执行了后边的命令,前边的命令会默认执行一次
- 1为清理生命周期
- 除此之外还有站点生命周期,不常用
maven中的packaging标签
- 项目的打包类型:pom、jar、war
- 如果不声明该元素,Maven会生成一个 JAR 包;
- 如果定义该元素的值为war,那会得到一个 WAR 包;
- 如果定义其值为 POM(比如是一个父模块),那什么包都不会生成。
- packing默认是jar类型,
- <packaging>pom</packaging> ---------> 父类型都为pom类型
- <packaging>jar</packaging> ---------> 内部调用或者是作服务使用
- <packaging>war</packaging> ---------> 需要部署的项目
maven packaging 标签细节
-
groupId:公司组织的名称 artifactId:项目名称 version:版本号
-
pom文件中除了GAV(groupId, artifactId, version)是必须要配置的,另一个重要的属性就是packing打包类型
- 项目中一般使用maven进行模块管理,每个模块下对应都有一个pom文件,pom文件中维护了各模块之间的依赖和继承关系。
- 项目模块化可以将通用的部分抽离出来,方便重用;修改一部分代码不再是build整个项目,缩短了build时间;此外各模块都有自己的pom文件,结构更清晰。
- 作为父级项目,有一个重要的属性,那就是modules,通过modules标签将项目的所有子项目引用进来,
在build父级项目时,会根据子模块的相互依赖关系整理一个build顺序,然后依次build。
即<modules><module></module></modules> + G、A、V、P + <modelVersion> - 而对于各个子项目,需要在其对应的pom文件开头使用<parent>标签申明对父级项目的引用,通过GAV实现。
对于子项目自己的GAV配置,GV如果不配置,则会从父级项目的配置继承过来。
即<parent>G、A、V</parent> + G、A、V + <modelVersion> - modelVersion 描述这个POM文件是遵从哪个版本的项目描述符
- modelVersion:指定了当前POM模型的版本,对于Maven2及Maven 3来说,它只能是4.0.0;因为,目前,没有其他模型
-
父工程:
<modelVersion>4.0.0</modelVersion>
<!-- 该工程把spring-boot-starter-parent作为父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.0</version>
<relativePath/>
</parent>
<!-- 关联父工程下边的子项目 -->
<modules>
<module>blog-api</module>
</modules>
<!-- 该工程基本信息 -->
<groupId>cn.edu.ctgu</groupId>
<artifactId>blog-parent</artifactId>
<version>1.0-SNAPSHOT</version>
<!-- 父工程仅仅用来做整个项目pom依赖管理 -->
<!-- packing声明为pom说明这是一个父工程 -->
<packaging>pom</packaging>
- 子工程:
<modelVersion>4.0.0</modelVersion>
<artifactId>blog-api</artifactId>
<parent>
<artifactId>blog-parent</artifactId>
<groupId>cn.edu.ctgu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
packaging 直接影响 Maven 的构建生命周期
- 任何一个Maven项目都需要定义POM元素packaging(如果不写则默认值为jar)。该元素决定了项目的打包方式。
-
项目的打包类型:pom、jar、war
- 如果不声明该元素,Maven会生成一个 JAR 包;
- 如果定义该元素的值为war,那会得到一个 WAR 包;
- 如果定义其值为 POM(比如是一个父模块),那什么包都不会生成。
- pom ---------> 父类型都为pom类型
- jar ---------> 内部调用或者是作服务使用
- war ---------> 需要部署的项目
-
除此之外,Maven默认还支持一些其他的流行打包格式,例如ejb3和ear。
你不需要了解具体的打包细节,你所需要做的就是告诉Maven,”我是个什么类型的项目“,这就是约定优于配置的力量。 -
需要注意的是:子类项目的packing值只能是war或者jar
-
一般来说:packing默认是jar类型。
- 1、如果是需要部署的项目,则需要打包成war类型,
- 2、如果只是内部调用或者是作服务使用,则推荐打包成jar类型。
- 3、如果只是作为父maven,则为pom类型
-
maven的依赖规范:<scope></scope>, 传递依赖下来的包是否能用
- 默认是compile
依赖范围 对于编译classpath有效 对于测试classpath有效 对于运行时classpath有效 例子 compile Y Y Y spring-core test - Y - Junit provided Y Y - servlet-api runtime - Y Y JDBC驱动 system Y Y - 本地的,maven仓库之外的类库
maven的依赖传递
- 什么是依赖传递?
-
在maven中,依赖是可以传递的,假设存在三个项目,分别是项目A、项目B、项目C,假设C依赖B,
B依赖A,那么我们可以根据maven项目依赖的特征知道项目C也依赖项目A
|----------------------------间接依赖---------------------------------|项目C -----直接依赖 ----> 项目B ----直接依赖-----> 项目A
-
maven如何解决依赖冲突
- 1.使用maven提供的依赖调解原则
- 1.第一声明优先原则
- 在pom文件中定义依赖,以先声明的依赖为准,其实就是根据坐标导入的顺序来确定最终使用过哪个传递过来的依赖
- 2.路径近者优先原则
- 直接依赖:项目中直接导入的jar包,就是该项目的直接依赖包
- 传递依赖:项目中没有直接导入的jar包,可以通过项目直接依赖jar包传递到项目中去
- 直接依赖优先于传递依赖
- 1.第一声明优先原则
- 2.排除依赖
- 3.锁定版本
- 采用直接锁定版本的方法确定依赖jar包的版本,版本锁定后则不考虑依赖的声明顺序或依赖的路径,
以锁定的版本为准添加到工程中,此方法在企业开发中经常使用 - 版本锁定的使用方式:
- 第一步:在dependencyManagement标签中锁定依赖的版本
- 第二步:在dependencies标签中什么需要导入的maven坐标
- 采用直接锁定版本的方法确定依赖jar包的版本,版本锁定后则不考虑依赖的声明顺序或依赖的路径,
分模块构建maven工程分析
-
第一种;按照业务模块进行拆分,每个模块拆分成一个maven工程,
例如将一个项目分为用户模块、订单模块、购物车模块等,每个模块对应就是一个maven工程 -
第二种:按照层进行拆分,例如持久层、业务层、表现层,每个层对应就是一个maven工程
- maven_parent:
- maven_pojo(继承maven_parent):
- maven_dao(继承maven_parent):
- maven_service(继承maven_parent):
- maven_web(继承maven_parent):
- maven_parent:
-
不管是上边的哪一种拆分方式,通常都会提供一个父工程,
-
子工程可以继承父工程,就可以使用在父工程中引入的依赖,继承的目的就是为了消除重复代码
将一些公共的代码和配置提取到父工程中进行统一的管理和配置
dependencyManagement 标签
- pom.xml文件中使用的dependencyManagement标签仅仅是用来锁定jar包版本,并没有真正的导入相应的jar包。
因此,如果项目中需要使用某个jar包,依旧需要在dependencies标签中使用dependency标签进行导入 - maven工程是可以分父子依赖关系的,凡是依赖别的项目后,拿到的别的项目的依赖包都属于传递依赖,
比如:当前parent项目,被son项目依赖。那么parent项目中的所有jar包都会传递到son项目中,这些jar包属于传递依赖
son项目的开发者,如果再在son项目中导入一套jar包,那么这些jar包属于直接依赖。此时直接依赖jar包就会把间接依赖jar包给 覆盖掉。为了防止该情况出现,我们就可以在parent项目中把jar包的坐标锁住,那么在其他依赖该项目的项目中,即便有同名jar包直接依赖,也无法覆盖 - dependencyManagement 标签中的dependencies 标签中的dependency中必须包含依赖的GAV,注意不能省略版本,因为dependencyManagement标签本身就是为了锁定版本的
工程和模块的区别
-
工程(project)不等于完整的项目,模块(module)也不等于完整的项目,一个完整的项目看的是代码,代码完整,就可以说这是一个完整的项目,一个完整的项目和此项目是工程还是模块没有关系
-
工程天生只能使用自己的内部资源,工程天生是独立的,后天可以后天其它工程或者模块建立关联管理;
模块天生不是独立的,模块天生是属于父工程的,模块一旦创建,所有父工程的资源都可以使用- 如:一个maven工程(project)内部有多个maven模块(module)。
- 该maven工程中的多个maven模块与maven工程是先天继承关系,即所有的maven模块的<parent>标签中写的都是maven工程的GAV;
而maven工程中的<modules>标签中包含了所有的maven模块。所有的maven模块都可以使用maven工程的资源(jar包) - 所有的maven模块之间可以相互引用,类似于引如jar一样,只需要在<dependencies>中的<dependency>中引入maven模块的GAV即可
- 该maven工程中的多个maven模块与maven工程是先天继承关系,即所有的maven模块的<parent>标签中写的都是maven工程的GAV;
- 如果一个工程希望和其他工程建立关联关系,则需要将其他工程install至本地的maven仓库,然后在该工程的pom.xml文件中导入其他工程的GAV即可
- 如:一个maven工程(project)内部有多个maven模块(module)。
-
子模块天生继承父工程,可以使用父工程的所有资源,子模块之间天生是没有任何关系的,如果需要建立管理关系,则需要在该模块中引入对应模块的GAV
-
父工程和子模块之间不用建立关系,继承关系是天生的,不需要手动建立(通过parent标签和module标签实现)
-
平级模块之间的引用叫做依赖,依赖不是先天的,依赖需要后天建立