有关于安装配置可以看我的另一篇文章:Maven下载安装配置与简介。
构建项目的生命周期和常用命令
这一节的内容熟记即可,要用了认得出来即可。
在Maven出现之前,项目构建的生命周期就已经存在。对项目进行清理、编译、测试、部署等一系列工作的这个过程,就是项目构建的生命周期。早期公司与公司之间,项目与项目之间的构建项目的方式有所不同,Maven对所有的构建过程进行了抽象和统一。
Maven的三个生命周期
这里介绍一下三个生命周期和它们所包含的事件。
清理工作:clean
>pre-clean:执行一些在clean之前的工作。
>clean:移除上一次构建产生的所有文件。
>post-clean:执行一些在clean之后立刻完成的工作。
核心工作:default
这个生命周期的事件很多。可以看下图:
而且在该生命周期里,执行某个事件会先把前面的事件依次执行一次。
产生报告与发布站点:site
>pre-site:执行一些在生成站点文档之前的工作。
>site: 生成项目的站点文档
>post-site:执行一些在生成站点文档之后完成的工作,为部署做准备
>site-deploy:将生成的站点文档部署到特定的服务器上
常用命令
这些是在cmd和powershell这种命令窗口使用的命令。
mvn clean:调用clean生命周期的clean阶段,清理上一次构建项目生成的文件,也就是compile产生的target目录 ;
mvn compile :编译src/main/java中的java代码成可直接运行的class文件 ,编译完成后maven项目会自动创建一个target目录来存储这些文件 ;
mvn test :编译并maven项目的src/test目录下的junit测试代码 ;
mvn package:将项目打包成可发布的文件,如jar或者war包,打包完成后将生成的文件存放在target目录中 ;
mvn install :发布项目到本地仓库 ;
pom.xml配置文件详解
根标签<project>
pom.xml文件的所有标签都在写在根标签<project>里面。
<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"><!-- 其他配置内容 --></project>
在<project>里常看见三个自动生成且被定义的属性:
xmlns:定义该maven项目的命名空间。
xmlns:xsi:定义一个与 XML Schema Instance(XSI)相关的命名空间前缀。xsi是这个命名空间的前缀,它本身并没有特别的含义,只是一个约定俗成的标识,用于关联特定的 XML Schema 验证规则。
xsi:schemaLocation:指定了POM 4.0.0 版本的xsd文件的位置,这用于验证pom.xml文件的结构是否符合 Maven 的规范。
命名空间:一种避免元素名称和属性名称冲突的机制。不同的开发人员或组织可能会使用相同的标签名称来表示不同的概念。例如,数学和化学相关项目里可能都有一个<element>标签,但它们代表完全不同的东西。命名空间就像是给每个开发人员和组织一个独特的 “书架”,将他们的标签和属性分开存放,这样就可以区分相同名称标签的不同含义
一级标签
一级标签有很多,这里讲几个常用的一级标签。
项目坐标(groupId、artifactId、version)
groupId:表示该项目所属的组织或团队的唯一标识符,商务中通常是公司或组织的反向域名。
artifactId:项目的唯一标识符,在groupId下唯一确定一个项目,通常是项目的名称。
version:指定项目的版本号。Maven在依赖管理和项目部署中通过版本号来管理项目的不同发布版本。
<groupId>org.example</groupId>
<artifactId>mavenText</artifactId>
<version>1.0-SNAPSHOT</version>
其中,SNAPSHOT表示这是一个开发中的版本,而不带SNAPSHOT的版本号表示正式发布的版本 。
上面是简单的项目坐标,除此之外,还有父工程子工程的继承关系。
这是项目结构:
其中,untitled还设置成了mavenText的子工程,下面是它的项目坐标:
<parent><groupId>org.example</groupId><artifactId>mavenText</artifactId><version>1.0-SNAPSHOT</version><relativePath/>
</parent>
这样的话父类所有的数据都会进入子类(比如所有加的第三方依赖)。
而子工程里<relativePath>元素的值留空则表示在这个示例中,Maven将查找父项目的POM文件,不需要额外的路径,这样可以避免去Maven仓库查找。当然,这种情况你不必要去刻意写出来,因为maven中不写relativePath的值,默认为../pom.xml,即查找父工程的pom.xml配置文件。
在父工程里面,也会通过<modules>标记子工程:
项目配置<properties>
<project><properties><!-- 项目的Java源码编译版本 --><maven.compiler.source>8</maven.compiler.source><!-- 项目的目标编译版本 --><maven.compiler.target>8</maven.compiler.target><!-- 源代码文件的字符编码 --><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties>//其他配置</project>
有些地方可能还会看到<properties>里面还有<java.version>标签,该标签用于指定项目所使用的 Java 版本,方便统一管理项目 Java 版本的配置。
默认会有的标签只有上面里面三个。
依赖管理<dependencies>
主要用于maven的依赖管理,在这里,你可以定义当前项目所需要依赖的jar包。定义之后,会优先在本地仓库进行查找,本地仓库没有,回去中央仓库查找。
有关于jar包的maven坐标获取方式,可以看我开头放置的文章链接,查看目录,找到《Maven简介》下的《maven依赖管理》,有详细说明。
<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>...<dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.9.RELEASE</version></dependency>...</dependencies></project>
groupId是maven官方给出的, 用于标识该依赖(jar包)所属的组织或者项目组,它遵循一种类似反向域名的命名规则,确保在全球范围内不同组织开发的库不会产生命名冲突。
artifactId是该依赖(jar包)的名字。
version是该依赖的版本,就像IDEA有2019、2024各种版本一样。
Maven高级特性
maven的高级特性有三个,分别为依赖管理、模块化和聚合。其中,依赖管理的一部分:依赖导入 在刚刚已经讲过,这部分不重复赘述。
依赖管理
依赖传递
在maven中,依赖是可以传递的,假设存在三个项目,分别是项目A,项目B以及项目C。假设C依赖B,B依赖A,根据maven项目依赖的特征可以知道项目C也依赖A。
自己写的项目需要打包后安装到本地仓库中,内容较多且与本文主要内容有点差别,为了文章内容不冗余,以后我会单独开一遍文章讲解。
这里用现成实例来举例。Web项目常常会依赖spring-webmvc,而spring-webmvc依赖了sping-aop、spring-beans等。最终的结果在我们的web项目中间接依赖了spring-aop、spring-beans等
依赖冲突
何为依赖冲突?
刚刚讲到了,项目和项目之间会间接依赖,假如我项目A依赖了servlet-api包,项目B也依赖了servlet-api包,但是B还依赖了项目A。这时候就会在servlet-api包处发生依赖冲突。
经典的例子:Web开发里servlet-api和jsp-api包不会在打包文件war里面,因为Tomcat本身就有s这两个的包(还记得初学Tomcat时,从Tomcat的文件里复制这两个jar包么)。
如果有依赖冲突还没有去解决,就会报java.lang.NoSuchMethodError异常。
常见的解决依赖冲突的办法有下面几种:
使用maven自带的依赖调节原则
该原则是自动执行的,不需要我们特意去设置。发生依赖冲突时:
1.在pom.xml文件里面,哪个依赖先声明,就使用那个依赖。
2.优先使用我们自己导入的jar包,依赖中传递的jar包排其次,直接依赖高于间接依赖。
排除依赖
我们需要在maven坐标处添加排除依赖的声明,使用<exclusions>标签和<exclusion>标签
以刚才提到的spring-webmvc举例
<dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>4.2.4.RELEASE</version><!-- 排除依赖的jar包 --><exclusions><exclusion><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></exclusion></exclusions></dependency>
锁定版本
虽然报依赖冲突异常不一定是不同版本导致的,但依赖冲突主要还是为了避免不同版本导致的相关问题,那么锁定版本也是一种可选方式。
锁定版本需要使用到<dependencyManagement>标签,该标签与<dependencies>同级,也是pom.xml文件的一个一级标签。
<!-- 锁定的jar包版本 -->
<dependencyManagement><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>5.0.2.RELEASE</version></dependency></dependencies>
</dependencyManagement><!-- 导入jar包时,不需要再设置版本 --><dependencies><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId></dependency>
</dependencies>
模块化
相信各位伙伴都接触了解maven了,MVC分包等应该也了解了。帮助我们构建项目是maven两大作用之一,通过子工程父工程等方式帮我们整合项目。
继承
在Java语言中,类之间是可以继承的,通过继承,子类就可以引用父类中非private的属性和方法。在maven工程之间也有继承,子工程继承父工程后,就可以使用在父工程中引入的依赖,以达到消除重复代码的目的。
子工程需要通过pom.xml文件里添加parent标签来设置父工程。
聚合
如何整合子工程?在父工程的pom.xml文件下添加一级标签<modules>,然后在里面标明该父工程的所有子工程,将其他maven工程聚合到一起,便于对这些项目进行统一操作。
例如拆分后的maven工程有多个,如果要进行打包,就需要针对每个工程分别执行打包命令,操作起来非常繁琐。这时就可以使用<modules>标签将这些工程统一聚合到maven工程中,需要打包的时候,只需要在此工程中执行一次打包命令,其下被聚合的工程就都会被打包了。
当然,父工程的打包方式一定要设置为pom,我们区分某个maven工程是否是父工程就看这个工程的打包方式是否为pom。