概述
Maven是Apache软件基金会组织维护的一款自动化构建工具。主要有两个作用:
- maven 工程对 jar 包的管理过程
- 项目的一键构建
构建概述
构建( build),是面向过程的( 从开始到结尾的多个步骤 ),涉及到多个环节的协同工作。构建过程的几个主要环节:
- ①清理:删除以前的编译结果,为重新做好准备。
- ②编译:将 Java源程序编译为字节码文件。
- ③测试:针对项目中的关键点进行,确保在迭代开发过程正性。
- ④报告:在每一次测试后以标准的格式记录和展示结果。
- ⑤打包:将一个含诸多文件的工程封装为一个压缩文件用于安装和步数。Java 工程对应的 jar 包,Web 工程对应的war包。
- ⑥安装:在 Maven 环境下,特指将打包的结果——jar包或war包安装到本地仓库中。
- ⑦部署:将打包的结果部署到远程仓库或者将 war包部署到服务器上运行。
图解编译结果与动态Web工程的区别:
开发过程中,所有的路径或配置文件中配置的类路径等都是以编译结果的目录结构为标准的
手动创建 maven 工程
配置 maven 环境
下载和安装Maven按如下步骤进行:
Step 1: 登录Maven站点下载Maven最新版。虽然Maven是基于Java的生成工具,具有平台无关的特性,但考虑到解压缩的方便性,通常建议Windows平台下载*.zip压缩包,而Linux平台下载.gz压缩包。
Step 2: 将下载的压缩文件解压缩到任意路径,解压缩后看到如下文件结构:
- bin:保存Maven的可执行命令。其中mvn和mvn.bat就是执行Maven工具的命令。
- boot:该目录只包含一个plexus-classworlds-2.6.0.jar。plexus-classworlds是一个类加载器框架,与默认的Java类加载器相比,它提供了更丰富的语法以方便配置,Maven使用该框架加载自己的类库。通常无需理会。
- conf:保存Maven配置文件的目录,该目录包含settings.xml文件,该文件用于设置Maven的全局行为。通常建议将该文件复制到/.m2/目录下(表示用户目录),这样可以只设置当前用户的Maven行为。
- lib:该目录包含了所有Maven运行时需要的类库,Maven本身是分模块开发的,因此用户能看到诸如maven-core-3.6.3.jar、maven-repository-metadata-3.6.3.jar等文件。此外,还包含Maven所依赖的第三方类库。
- LICENSE、README.txt等说明文档。
Step 3: Maven的运行需要如下两个环境变量:
- JAVA_HOME:该环境变量应指向JDK安装路径。如果已经成功安装了Tomcat,则环境变量应该是已经正确的
- M2_HOME:该环境变量应指向Maven安装路径。
提示:Maven安装路径就是前面释放Maven压缩文件的路径。Maven安装路径下应该包含bin、boot、conf和lib4个文件夹。
Step 4: Maven工具的关键命令就是%M2_HOME%/bin路径下的mvn.bat命令,如果希望操作系统可以识别该命令,还应该将%M2_HOME%/bin路径添加到操作系统的PATH环境变量之中。
Step 5(可选): 在%M2_HOME%/conf/settings.xml中添加如下代码,因为使用Maven过程中涉及很多插件的下载,而这些插件都是在国外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>
经过上面5个步骤,Maven安装成功,启动命令行窗口,输入如下命令(如果未将%M2_HOME%/bin路径添加到操作系统的PATH环境变量之中,则输入mvn.bat的全路径):mvn help:system
通过该命令应该先看到Maven不断地从网络下载各种文件,然后会显示如下两类信息:
- System Properties
- Environment Variables
如果能看到Maven输出如上两类信息,则表明Maven安装成功。
创建maven 工程
-
按下面结构创建文件属于maven的文件目录
目录结构 Hello 工程名 |---src 源码 |---|---main 放主程序 |---|---|---java 存放java源文件 |---|---|---resources 存放框架或其他工具的配置文件 |---|---test 存放测试程序 |---|---|---java 存放java源文件 |---|---|---resources 存放框架或其他工具的配置文件 |---pom.xml Maven的核心配置文件
-
编写 POM.xml
<?xml version="1.0" ?> <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> <groupId>com.atguigu.maven</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Hello</name> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.0</version> <scope>test</scope> </dependency> </dependencies> </project>
-
在
src/main/java/com/atguigu/maven
目录下新建文件Hello.java
<?xml version="1.0" ?> <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> <groupId>com.atguigu.maven</groupId> <artifactId>Hello</artifactId> <version>0.0.1-SNAPSHOT</version> <name>Hello</name> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.0</version> <scope>test</scope> </dependency> </dependencies> </project>
-
利用
mvn compile
进行编译
5. 利用 mvn test
Maven 的核心概念
Maven 核心点的九大概念: POM,约定的目录结构,坐标,依赖管理,仓库管理,生命周期,插件和目标,继承,聚合
Maven目录结构
目录结构
Hello 工程名
|---src 源码
|---|---main 放主程序
|---|---|---java 存放java源文件
|---|---|---resources 存放框架或其他工具的配置文件
|---|---test 存放测试程序
|---|---|---java 存放java源文件
|---|---|---resources 存放框架或其他工具的配置文件
|---pom.xml Maven的核心配置文件
Maven常用命令:
- mvn clean:将target目录删除,但是已经 install 到仓库里的包不会删除
- mvn compile:编译主程序
- mvn test-compile:编译测试程序
- mvn test:执行测试
- mvn package:打包
- mvn install:安装
- mvn deploy:部署、生成站点
pom.xml
pom.xml对于Maven工程是核心配置文件,与构建过程相关的一切设置都在这个文件中进行配置。重要程度相当于web.xm|对于动态Web工程
坐标gav
数学中的坐标:
- 在平面上,使用
x、y
两个向量可以唯一的定位平面中的任何一个点 - 在空间上,使用
x、y、z
三个向量可以唯一的定位空间中的任何一个点
Maven的坐标: 使用三个向量在仓库中唯一 定位一个Maven工程
- groupid:公司或组织域名的倒序+项目名 :例如 com.baidu.projectname
- artifactid:模块名
- version:版本
Maven 工程的坐标与仓库中路径的对应关系
<groupId> org.springframework </groupId>
<artifactId> spring-core </artifactId>
<version>4.0.0.RELEASE </version>
与下面路径的jar相对应:
org/springframework/spring-core/4.0.0.RELEASE/spring-core-4.0.0.RELEASE.jar
注意:我们的Maven 工程必须执行安装操作才能够进入仓库,安装的命令为
mvn install
仓库repository
仓库的分类
- 本地仓库:当前电脑上部署的仓库目录,为当前电脑上多有Maven工程服务
- 远程仓库
- 私服:搭建在局域网环境中,为局域网范围内的所有Maven工程服务
- 中央仓库:架设在Internet上,为全世界所有Maven工程服务
- 中央仓库镜像:为了分担中央仓库的流量,提升用户访问速度
- 私服:搭建在局域网环境中,为局域网范围内的所有Maven工程服务
当Maven需要使用某个插件或JAR包时,Maven的搜索顺序为:本地资源库->远程资源库->中央资源库
- 当Maven从中央资源库下载了某个插件或JAR包时,Maven都会自动在本地资源库中保存它们,因此只有当Maven第一次使用某个插件或JAR包时,才需要通过网络下载。
仓库中的文件:
- Maven自身所需的插件
- 第三方框架或工具的jar包
- 自己开发的Maven工程
※不管是什么样的 jar包,在仓库中都是按照坐标生成目录结构所以可通过统一的方式查询或依赖。
依赖
依赖的目的
当 A jar 包用到了 B jar 包中的某些类是,A就对B产生了依赖。
在项目中 可以用使用 dependency
标签来指定被依赖的 jar 包的坐标。
![在这里插入图片描述](https://img-blog.csdnimg.cn/f42103a5d68e4e1babb180197275e95f.png?x-oss-process=im
依赖的范围:
·dependency· 中出来 jar 包的坐标之外,还存在 scope 设置,即为 依赖的范围。范围的可选值有三种:
compile,test和provided。
【1】项目结构角度分析 compile 和 test 的区别:
以第一个程序的 hello 为例,该项目中测试程序需要 junit,而主程序不需要。所以test的依赖范围仅仅对测试程序有效。
【2】从开发和运行的角度分析compile 和provided 的区别
【3】有效性总结
依赖的传递性
A 依赖 B,B依赖 C,A能够使用C 的条件为:当B 依赖 C的范围是compile时就可以依赖。如果不是就不能依赖。
依赖排除
如果我们我们在当前工程中引入了一个依赖A,而A有依赖了B,那么 Maven 会自动将 A 依赖的B引入到当前工程。但是有时候由于版本冲突,或者B是一个不稳定版本,这时我们可以在引入A的时候将B排除。
举例: 如下图所示,如果我们想排除下面的依赖包
那么我们的配置中应该加上 exclusion
相关字样:
排除后的结果如下:
统一管理所依赖的 jar 包版本
为了方便升级框架,可以将 jar 包的版本信息统一提取出来
- 统一声明版本号,可以理解为创建一个变量专门存取版本号
<properties>
<cvzhanshi.spring.version>4.0.0.RELEASE</cvzhanshi.spring.version>
</properties>
- 在需要版本好的地方应用即可
<version>${cvzhanshi.spring.versio}</version>
其实properties标签配合自定义标签声明数据的配置并不是只能用于声明依赖的版本号。凡是需要统一声明后再弓|用的场合都可以使用(比如编码方式等)
<properties>
<cvzhanshi.spring.version>4.0.0.RELEASE</cvzhanshi.spring.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
依赖的原则:解决 jar 包冲突的方法
- 路径最短者优先
- 当路径相同时,先声明这优先
这里的声明指的是 dependency 标签配置的先后顺序
生命周期
各个构建环节执行的顺序:不能打乱顺序,必须按照既定的正确顺序来执行
Maven的核心程序中定义了抽象的生命周期,生命周期中各个阶段的具体任务是由插件来完成的
- Maven核心程序为了更好的实现自动化构建,按照这一的特点执行生命周期中的各个阶段:不论现在要执行生命周期中的哪一个阶段,都是从这个生命周期最初的位置开始执行
Maven包含三个基本的生命周期。
- clean生命周期:在进行构建之前的一些清理工作。
- default生命周期:编译,测试,打包,安装和部属等。
- site生命周期:生成项目报告,站点,发布站点。
可以使用 mvn clean install site
来 运行整个流程。
每套生命周期都是由一组阶段组成, Maven可以支持许多不同的生命周期,最常用的生命周期是Maven默认的生命周期。我们平时输入的命令行总会对应某个特定的阶段。如 mvn clean 表示 Clean 周期的一个阶段。
Clean 生命周期
clean生命周期用于在构建项目之前进行一些处理工作,该生命周期包含如下三个核心阶段:
- pre-clean:执行一些在 clean 之前需要完成的工作
- clean:执行清理,移除上一次构建生成的文件
- post-clean:最后清理,执行一些需要在clean之后立即完成的工作
Site 生命周期
- pre-site 执行一些需要在生成站点文档前完成的操作。
- site: 生成项目的站点文档
- post-site:执行一些需要在生成站点文档之前的操作工作,并且为部署做准备
- site-deploy:将生成站点文档1部署到特殊的服务器上
Default 生命周期
- validate:验证项目是否正确
- generate-sources:生成源代码
- process-sources:处理源代码
- generate-resources:生成项目所需的资源文件
- process-resources:复制资源文件至目标目录
- compile:编译项目的源代码
- process-classes:处理编译生成的文件
- generate-test-sources:生成测试源代码
- process-test-sources:处理测试源代码
- generate-test-resources:生成测试的资源文件
- process-test-resources:复制测试的资源文件至测试目标目录
生命周期的自动构建
运行任何一个阶段的时候,它前面的所有阶段都会被运行,例如我们使用 mvn install
时,代码会被编译,测试,打包。即自动完成构建,这也是学习生命周期的重要性。
插件和目标(plugins and goal)
除了可以使用Maven官方、第三方提供的各种插件之外,也可以开发自定义插件,通过自定义插件来完成任务。
每个插件又可以包含多个可执行的目标(goal),使用mvn命令执行指定目标的格式如下:
mvn <plugin-prefix>:<goal> -D<属性名>=<属性值> ...
当使用mvn运行Maven生命周期的指定阶段时,各阶段所完成的工作其实也是由插件实现的。插件目标可以绑定到生命周期的各阶段上,每个阶段可能绑定了零个或者多个目标。随着Maven沿着生命周期的阶段移动,它会自动执行绑定在各特定阶段上的所有目标。
Maven生命周期的各阶段也是一个抽象的概念,
- 对于软件构建过程来说,默认的生命周期被划分为compile、test、package、install、deploy这5个阶段,但这5个阶段分别运行什么插件、目标,其实是抽象的——这些阶段对于不同项目来说意味着不同的事情。
- 例如,package阶段在某些项目中对应于生成一个JAR,它意味着“将一个项目打成一个JAR包”;而在另一个项目里,package阶段可能对应于生成一个WAR包。
开发时可以将任意插件绑定到指定生命周期,如下:
<build>
<plugins>
<plugin>
<!-- 下面3个元素顶一个exec插件的坐标 -->
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.3.1</version>
<executions>
<execution>
<!-- 指定绑定到compile阶段 -->
<phase>compile</phase> <!-- ① -->
<!-- 指定运行exec插件的java目标 -->
<goals>
<goal>java</goal> <!-- ② -->
</goals>
<!-- configuration元素用于为插件的目标配置参数 -->
<configuration>
<!-- 下面元素配置mainClass参数的值为:org.fkjava.mavenqs.App -->
<mainClass>org.fkjava.mavenqs.App</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
- ①号配置代码指定该插件、目标绑定到compile阶段;
- ②号配置代码指定运行exec插件的java目标。
通过上面这段配置,即可将exec插件的java目标绑定到compile阶段。
继承
为什么需要继承
由于非 compile范围的依赖信息是不具有传递性的,所以需要工程单独进行配置。如下:
此时如果项目需要将各个模块的junit版本统一为 4.9,那么到各个工程中手动修改无疑是非常不可取 的。 使用 继承机制就可以将这样的依赖信息统一提取到父工程模块中 进行统一管理。
举例:将 junit 改为4.9
-
创建父工程
创建父进程和创建一般的 java 工程操作一样,唯一需要注意的是打包方式必须使用 pom
-
在子工程中引用父工程
此时如果子工程的 groupId 和 version 与父工程的重复则可以删除。 -
在父工程中管理依赖(即引入我们的 Junit 4.9),在 Paren项目中的
dependency
标签,用dependencyManagement
标签括起来<dependencyManagement> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.9</version> <scope>test</scope> </dependency> </dependencies> </dependencyManagement>
-
在子项目中重新指定需要的依赖,删除范围和版本号
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> </dependencies>
聚合
在多个工程拆分为模块后,需要手动逐个安装到仓库后依赖才会生效。修改源码后才需要逐个手动进行 clean 操作。而使用了聚合之后就可以批量进行 Maven 工程的安装和清理工作了。
步骤
在总的聚合过重使用 modules/module
标签进行组合,指定模块工程的相对路径即可。
<modules>
<module>../Hello</module>
<module>../HelloFriend</module>
<module>../MakeFriends</module>
</modules>
dependency的子元素概览
<groupId…/>
:指定依赖框架或依赖类库所属组织ID<artifactId…/>
:指定依赖框架或依赖类库的项目名<version…/>
:指定依赖框架或依赖类库的版本号<scope…/>
:指定依赖库起作用的范围。该子元素可接受 compile、provided、test、system、runtime、import等值<type…/>
:指定依赖框架或依赖类库的类型,该元素的默认值是jar=。另外,还可以只指定war、ejb-client、test-jar等值<optional…/>
:该元素指定该依赖库是否为可选的<classifier…/>
:JDK版本号,如jdk14或hdk15等。用于指定被依赖的JAR包是在哪个版本下编译的。<exclusions../>
:该元素用于排除依赖
上面说到的 <scope.../>
元素用于指定依赖库起作用的范围,该元素可指定如下值:
- compile:默认的范围,编译、测试、打包时需要
- provided:表示容器会在runtime时提供
- runtime:表示编译时不需要,但测试和运行时需要,最终打包会包含进去
- test:只用于测试阶段
- system:与provided类似,但要求该JAR是系统中自带的
- import:继承父POM文件中用dependencyManagement配置的依赖,import范围只能在dependencyManagement元素中使用(为了解决多继承
Maven 的库站
可以在 https://mvnrepository.com/ 中搜索需要的 jar 包的依赖信息。
maven的概念模型图如下:
Maven 与 IDEA
①. idea集成maven插件
-
idea中maven配置(全局setting),configure下的settings
-
找到Maven将对应的改成本地仓库中的地址
-
-DarchetypeCatalog=internal
这个参数的意思是:如果我们使用maven为我们提供好的骨架来创建maven工程,一般是要联网的.
为了在不联网的情况下我们可以正常创建工程,配了这样一个参数,只要我们之前联网下载过之前相关创建工程的插件,它就会从本地仓库找到对应插件,而不会联网下载
- 局部setting
②. 使用骨架创建maven的java工程
③. idea 中创建一个maven的web工程(使用骨架)
这个窗口基本上不用修改什么,但是这样会比较慢,有时候如果网速不好,就会卡的比较久
- 这是因为maven这个骨架会从远程仓库加载archetype元数据,但是archetype又比较多,所以比较卡,这时候可以加个属性
archetypeCatelog=internal
,表示仅使用内部元数据:
点击 Finish 后开始创建工程,耐心等待,直到出现如下界面。
手动添加 src/main/java 和resource 目录,如下图右键 main 文件夹NewDirectory
点Project Struct,设置源码文件夹和资源文件夹:IDEA202.3:
tomcat部署
④. 创建一个maven的web工程(不用骨架)
-
点击new,点击project
-
点击maven
-
点击next后,填写对应的信息,一直next
-
创建后页面如下
⑤. 包的引入:以Servlet为例
如上所示,此时我们没有导入 HTTPServlet 的jar包
引入包的具体步骤如下:
-
直接打开hello_maven工程的pom.xml文件,再添加坐标
<dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> </dependency> </dependencies>
可以先写 artifacID,后面两个选项IDEA就能够很好的定位出来
结果显示
5.5: 冲突的解决
如果此时还需要导入 maven自带的Tomcat中的jar包,那么此时我们可以 通过添加依赖范围的方法来避免冲突,如下,如果存在两个 Servlet 包,可以通过 添加 scope
关键字的方法设置依赖范围:
<!--放置的都是项目所要依赖的jar包-->
<!--provided的意思是编译时使用它,运行时不使用-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>jsp-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
⑥. tomcat插件和jdk插件
- 点击setting,进行一系列的配置
2. 只需要打tomcat7和jdk会自动出来提示
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<port>8888</port>
</configuration>
</plugin>
<!--jdk插件-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<target>1.8</target>
<source>1.8</source>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
⑦. maven 工程运行调试
端口占用处理
问题:重新执行 tomcat:run 命令重启工程,重启之前需手动停止 tomcat,否则报下边的错误:
断点调试:点击如图所示选项
在弹出窗口中填写如下信息
如上图红框选中的两个按钮,左侧是正常启动,右侧是 debug 启动
⑨. IDEA中导入Maven工程(module)
- ①. 新建一个空的project作为工作空间
- ②. 在项目结构中导入或移除 module
- ③. 选择要导入的Module:
- ④. 选择导入方式
- ⑤. 选择要导入的项目
⑥. 设置导入module所使用的JDK
⑦. 导入后项目结构
⑧. 导入后视图
⑩. 修改目录结构
maven有一个很重要的功能是规范项目,标准的项目结构如下所示
但是你会发现默认创建的项并非是完整的,如写源代码的目录没有,添加方法如下:
-
当前项目结构如下:
-
添加相应的目录,选择打开项目结构:
-
目标位置右键添加目录