一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第5天,点击查看活动详情。
1、Maven简介
1. 什么是Maven
Maven是一个项目管理工具,它包含了一个项目对象模型(POM:Project Object Model),一组标准集合(目录结构是非常标准的),一个项目生命周期(Project Lifecycle),一个依赖管理系统(Dependency Management System),和用来运行定义在生命周期阶段(phase)中插件(plugin)目标(goal)的逻辑。
简的来说Maven是:一个项目管理工具,将项目开发和管理过程抽象成一个项目对象模型(POM)
PS:Maven是由Java编写的,所以他管理的东西统统以面向对象的形式进行设计的,最终他把一个项目看成一个对象(该对象也就是POM)
- 项目对象模型(Project Object Model)
一个Maven工程都有一个pom.xml文件,通过pom.xml文件定义项目的坐标、项目依赖、项目信息、插件目标等。
- 依赖管理系统(Dependency Management System)
通过Maven的依赖管理对项目所依赖的jar包进行统一管理。
- 一个项目生命周期(Project Lifecycle)
使用Maven完成项目的构建,项目构建包括:清理、编译、测试、部署等过程,Maven将这些过程规范为一个生命周期。
如下所示是生命周期的各个阶段:
Maven项目的架构
2. Maven能解决什么问题
-
当遇到要引入各种jar包时,会很太麻烦!因为每次想要用的时候都要手动导入,有时候还会遇到版本冲突的问题,导致令人抓狂(Maven可以帮我们很方便的导入各种jar包)
-
我们辛辛苦苦写好了Java文件,可是只懂0和1的白痴电脑却完全读不懂,需要将它编译成二进制字节码文件。幸好现在各种集成开发工具(Eclipse、IDEA)也可以帮我们完成这种编译的过程。其实maven也可以帮我们完成~,但Maven完成的不仅仅时编译。它可以帮我们自动的编译、自动的测试、自动的打包、自动的安装、自动的运行。(其实就是Maven可以帮我们管理项目的生命周期)
-
Maven可以帮我们自动的去测试
-
Maven可以帮我们自动的去部署
2、Maven相关知识
1. Maven仓库的分类
仓库:用于存储资源,包含各种jar包
- 本地仓库:
用来存储从私服或中央仓库下载的插件和jar包。自己电脑上存储资源的仓库,连接远程仓库获取资源 - 远程仓库
非本机电脑上的仓库,为本地仓库提供资源
1. 私服:如果本地需要插件或者jar包,本地仓库没有,默认去私服下载。私服可以在互联网内也可以在局域网内。
PS:有时候我们也会把远程仓库默认叫为私服。Maven的仓库总体还是分为两大类的(本地仓库、远程仓库)。
2. 中央仓库:在Maven软件中内置一个私服地址repo1.maven.org/maven2 ,它是中央仓库,服务于整个互联网(全球唯一的),它是由Maven团队自己维护,里面存储了大部分开源的jar包,它包含了世界上大部分流行的开源项目构件。
私服的作用:
保存具有版权的资源,包含购买或自主研发的jar- 中央仓库中的jar都是开源的,不能存储具有版权的资源
一定范围内共享资源,仅对内部开放,不对外共享
小结:
当本地仓库没有所需要的jar包时,会先访问远程仓库(如果没有搭建远程仓库的话,就直接去访问中央仓库),如果远程仓库没有的话,再去中央仓库下载。
远程仓库的好处:
1. 提高下载效率( 因为中央仓库是国外的。国内要去下载国外资源是很慢的。可以提前在远程仓库下载好,之后让本地仓库访问就很快了)。
2. 可以在自己的远程仓库里添加自己的jar包
2. Maven的作用
- Maven的依赖管理
Maven的一个核心特性就是 依赖管理。传统的WEB项目中,我们必须将工程所依赖的jar包复制到工程中,导致了工程变得很大。然而Maven工程中不直接将jar包导入到工程中,而是通过在pom.xml文件中添加所需jar包的坐标,这样就很好的避免了jar包被直接引入进来,在需要用到jar包的时候,只要查找pom.xml文件,再通过pom.xml文件中的坐标,到一个专门用于”存放jar包的仓库”(Maven仓库)中根据坐标从而找到这些jar包,再把这些jar包拿去运行即可。
- 项目的一键构建
我们的项目,往往都要经历编译、测试、运行、打包、安装,部署等一系列过程。
那么,什么是构建呢?
构建指的是:项目从编译、测试、运行、打包、安装,部署整个过程都交给Maven进行管理,这个过程称为构建。
那么,什么又是一键构建呢?
一键构建指的是:整个构建过程,使用Maven一个命令可以轻松完成整个工作。
Maven的作用简单小结:
项目构建:提供标准的、跨平台的自动化项目构建方式依赖管理:方便快捷的管理项目依赖的资源(jar包),避免资源间的版本冲突问题(就是管理jar包)依赖:指当前项目运行所需的jar包,一个项目可以设置多个依赖。
- Maven规范化构建流程如下:
3. Maven工程的目录结构
由于早期大家建立目录非常随意,导致Maven设置了一个统一的开发结构。
统一开发结构:提供标准的、统一的项目结构
作为一个Maven的Web工程文件,它的src目录和pom.xml是必备的。
进入src目录后,我们发现它里面的目录结构如下:
src/main/java —— 存放项目的.java文件
src/main/resources —— 存放项目资源文件,如spring, hibernate配置文件
src/test/java —— 存放所有单元测试.java文件,如JUnit测试类
src/test/resources —— 测试资源文件
target —— 项目输出位置,编译后的.class文件会输出到此目录
pom.xml —— maven项目核心配置文件
- Java工程结构与Web工程结构的区别:
注意:如果是普通的java项目,那么就没有webapp目录。
4. Maven常用命令(了解)
我们可以在cmd中通过一系列的maven命令来对我们的Maven项目文件进行编译、测试、运行、打包、安装、部署。
-
compile compile是maven工程的
编译命令,作用是将src/main/java下的文件编译为.class文件输出到target目录下。Ctrl + R输入cmd进入命令状态,执行mvn compile,即可生成.class文件 -
test test是maven工程的
测试命令mvn test,会执行src/test/java下的单元测试类。
cmd执行mvn test执行src/test/java下单元测试类 -
clean clean是maven工程的
清理命令,执行clean会删除target目录及内容。 -
package package是maven工程的
打包命令,对于java工程执行package打成jar包,对于web工程打成war包。 -
install install是maven工程的
安装命令,执行install将maven打成jar包 或war包发布到本地仓库 -
Maven指令的生命周期 maven对项目构建过程分为
三套相互独立的生命周期。
Clean Lifecycle 在进行真正的构建之前进行一些清理工作。
Default Lifecycle 构建的核心部分,编译,测试,打包,部署等等。
Site Lifecycle 生成项目报告,站点,发布站点。
3、Maven的坐标
0. 坐标
-
什么是坐标 Maven中的坐标
用于描述(识别)仓库中资源的位置。 -
Maven坐标主要组成
groupld:定义当前Maven项目隶属组织名称(通常是域名反写,例如: org.mybatis)
artifactld:定义当前Maven项目名称(通常是模块名称,例如CRM、SMS)
version:定义当前项目版本号
packaging:定义该项目的打包方式(不属于maven坐标)
- Maven坐标的作用
使用唯一标识,唯一性定位资源位置,通过该标识可以将资源的识别与下载工作交由机器完成。讲人话就是:Maven坐标就起一个作用 => 在仓库中帮你找到这个资源。(该资源并不是非程序员用的,是给Maven工具用的。他会按你给的这个坐标,去查找这个资源、下载这个资源、使用这个资源)
- 全局setting与用户setting区别
全局settting定义了当前计算机中Maven的公共配置
用户settting定义了当前用户的配置
坐标的简单小结:
1. 坐标是识别资源用的位置。
2. 让Maven这款工具帮我们找资源的。
3. 由三部分组成:组织ID、项目ID、版本号
1. pom.xml文件的坐标
<!-- 项目名称,定义为组织名+项目名,类似包名 -->
<groupId>com.itheima</groupId>
<!--模块名称-->
<artifactId>hello_maven</artifactId>
<!--当前项目版本号,snapshot为快照版本即非正式版本,release为正式发布版本-->
<version>0.0.1-SNAPSHOT</version>
<packaging>:打包类型
jar:执行package会打成jar包 `> java工程
war:执行package会打成war包 `> web工程
pom :用于maven工程的继承,通常父工程设置为pom
添加jar包的坐标时,还可以指定这个jar包将来的作用范围。
<!-- 指定这个jar包将来的作用范围 -->
<scope>compile</scope>
2. 坐标的来源方式
- 可以从网上搜索(去 Maven的坐标库中(mvnrepository.com )查询并复制坐标)
- 先从中央仓库中把需要的jar包全部下载下来,之后再利用快捷键(IDEA:Alt + insert 插入Dependency,然后输入要导入的jar包的关键词)导入
3. 依赖范围
下面还有一个依赖范围,但它们两个是一样的。一个详,一个略。
A依赖于B,需要在A的pom.xml文件中添加B的坐标,添加坐标时需要指定依赖范围。 依赖范围包括:
-
compile:编译范围,
**指A在编译时依赖B,此范围为默认依赖范围**。编译范围的依赖会用在编译、测试、运行,由于运行时需要所以编译范围的依赖会被打包。 -
provided:
provided依赖只有在当JDK或者一个容器已提供该依赖之后才使用。provided依赖在编译和测试时需要,在运行时不需要,比如:servlet api被tomcat容器提供。 -
runtime:runtime依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如:jdbc的驱动包。由于运行时需要所以runtime范围的依赖会被打包。
-
test:test范围依赖在编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用,比如:junit。由于运行时不需要所以test范围依赖不会被打包。
-
system:system范围依赖与provided类似,但是你必须显式的提供一个对于本地系统中JAR文件的路径,需要指定systemPath磁盘路径,system依赖不推荐使用。
在maven-web工程中测试各各scope。
测试总结:
默认引入的jar包 ------- compile【默认范围可以不写】(编译、测试、运行都有效)
servlet-api 、jsp-api ------- provided(编译、测试有效,运行时无效防止和tomcat下jar冲突)
jdbc驱动jar包 ---- runtime(测试、运行有效)
junit ----- test(测试有效)
依赖范围 由强到弱 的顺序是:compile > provided > runtime > test
1. 解析为什么添加servlet的依赖包的时候不指定 scpoe == provided 报错的原因。
首先,如果不指定依赖范围为provided时,将会报“Class com.kaf.servlet.DemoServlet is not a Servlet”错误。
这是由于tomcat容器里已经有了servlet的jar包了,如果你导出的时候还导出servlet的话会产生冲突!(使用默认的依赖范围 or runtime的依赖范围)所以不应该将该jar包设置为运行时有效!
PS:servlet 、 jsp 由于tomcat服务器里都有他们的依赖包了,所以要避免导出! 应该将依赖范围设置成 provided ==> 编译、测试时有效
2. 解析为什么给JDBC驱动包的依赖范围设置成默认范围也没事?
首先JDBC,它是由sun公司提供的一套 接口,具体的实现类由各个数据库厂商来实现。
所以他在编译时即使导入jar包也可以编译通过!
其次,tomcat里也没有对应的jar包,所以在运行时也是save的~
3. 那么为什么JDBC驱动包要设置成runtime 测试、运行时有效的呢?
因为JDBC是由sun公司提供的,这代表着Java内嵌了该接口了。即使你不导包也没事,只不过在运行的时候要去找具体的实现类罢了
所以把它设置成测试、运行时有效就OK,但是如果你想要设置成编译、测试、运行有效也是可以的。
PS:只有provided最为特殊,不加会对程序带来影响!
但是如果你对依赖范围熟悉的话,可以都添加,这样显着你很牛逼,很厉害😜
4、依赖管理
1. 依赖配置
依赖:指当前项目运行所需的jar包,一个项目可以设置多个依赖。
格式:
2. 依赖传递
依赖具有传递性
- 直接依赖:
在当前项目中通过依赖配置建立的依赖关系 - 间接依赖:
被资源的资源如果依赖其他资源,当前项目间接依赖其他资源
没有说谁是直接依赖于谁 or 谁间接依赖于谁的。这是一个相对概念
依赖传递的冲突问题
- 路径优先:
当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高(就近原则) - 声明优先:
当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的(先来后到) - 特殊优先:
当同级配置了相同资源的不同版本,后配置的覆盖先配置的(同名覆盖原则)
依赖冲突描述:
我们根据某个项目为根,对他所依赖的资源进行深度的标注。如:直接依赖称为一度资源,直接依赖的直接依赖称为二度资源...
当出现冲突的时候,一度的覆盖二度的(层级越深,优先级越低 => 路径优先)。
当遇到相同层级的看配置的顺序是否靠前(配置顺序靠前的覆盖配置顺序靠后的 => 声明优先)。
当同个项目里配置相同资源时,后配置的覆盖先配置的。
3. 可选依赖
可选依赖指:
对外隐藏当前所依赖的资源——不透明(该依赖能被使用)(别人不想让你看到他在干嘛)
在依赖里添加:true (默认是false) 即可
PS:true 是添加在自己开发的工程中的(即 它无法隐藏别人项目里的依赖资源)。如果想去掉别的jar包里的依赖得使用
4. 排除依赖
排除依赖指:
主动断开依赖的资源,被排除的资源无需指定版本——不需要(该依赖不能被使用)(你不想使用这个依赖资源)
排除依赖和可选依赖是一样的作用?❌🙅❌
**`可选依赖是私房钱,控制别人能不能看到你用什么。
排除依赖是主动的断开间接依赖的资源。`**
5. 依赖范围
-
依赖的jar默认情况可以在任何地方使用。也可以通过scope标签设定其作用范围 -
作用范围
1、主程序范围有效(main文件夹范围内)
2、测试程序范围有效(test文件夹范围内)
3、是否参与包(package指令范围内)
为什么provided不参与打包?
假设程序中用到了servlet3.0,然后你把这个3.0的jar包打包到war包里了,并且上传到服务器里了。然后tomcat服务器也有一个servlet API。此时就有可能产生冲突!(如果tomcat服务器的servlet与你项目中的servlet的版本号一致的话,没事。但如果不一样就会报错。=> 你的3.0会先加载,但tomcat不支持,这就会报错)所以我们要将servlet的依赖范围定义为:provided
为什么JDBC驱动包的依赖范围要设置成runtime?
因为JDBC是由sun公司提供的,这代表着Java内嵌了该接口了。即使你不导包也没事,只不过在运行的时候要去找具体的实现类罢了。因此将它的依赖范围设置为runtime
依赖范围具有传递性(了解即可)
带有依赖范围的资源在进行传递时,作用范围将受到影响
5、生命周期与插件
1. 项目构建生命周期
Maven构建生命周期描述的是
一次构建过程经历了多少个事件
- Maven对项目构建的生命周期划分为3套
- clean:清理工作
- default:核心工作,例如编译,测试,打包,部署等
- site:产生报告,发布站点等
1、clean生命周期
2、default生命周期
3、site生命周期
生命周期控制的是:在进行构建任务的时候执行的过程有哪些。每个过程都有一件事。 那么这些事情是谁在做呢?——插件Plugin
2. 插件
插件与生命周期内的阶段绑定在一起,在执行到对应生命周期时执行对应的插件功能
默认maven在各个生命周期上绑定有预设的功能
通过插件可以自定义其他功能
小结:
生命周期:运行的阶段 Phase
插件:为了支持生命周期的那些事(设置)