简单了解Maven

124 阅读15分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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)

  1. 项目对象模型(Project Object Model)

一个Maven工程都有一个pom.xml文件,通过pom.xml文件定义项目的坐标、项目依赖、项目信息、插件目标等。

  1. 依赖管理系统(Dependency Management System)

通过Maven的依赖管理对项目所依赖的jar包进行统一管理。

  1. 一个项目生命周期(Project Lifecycle)

使用Maven完成项目的构建,项目构建包括:清理、编译、测试、部署等过程,Maven将这些过程规范为一个生命周期。

如下所示是生命周期的各个阶段: image.png

Maven项目的架构 image.png

2. Maven能解决什么问题

  1. 当遇到要引入各种jar包时,会很太麻烦!因为每次想要用的时候都要手动导入,有时候还会遇到版本冲突的问题,导致令人抓狂(Maven可以帮我们很方便的导入各种jar包

  2. 我们辛辛苦苦写好了Java文件,可是只懂0和1的白痴电脑却完全读不懂,需要将它编译成二进制字节码文件。幸好现在各种集成开发工具(Eclipse、IDEA)也可以帮我们完成这种编译的过程。其实maven也可以帮我们完成~,但Maven完成的不仅仅时编译。它可以帮我们自动的编译、自动的测试、自动的打包、自动的安装、自动的运行。(其实就是Maven可以帮我们管理项目的生命周期

  3. Maven可以帮我们自动的去测试

  4. Maven可以帮我们自动的去部署

2、Maven相关知识

1. Maven仓库的分类

仓库用于存储资源,包含各种jar包

  1. 本地仓库用来存储从私服或中央仓库下载的插件和jar包。自己电脑上存储资源的仓库,连接远程仓库获取资源
  2. 远程仓库

非本机电脑上的仓库,为本地仓库提供资源

   1.  私服如果本地需要插件或者jar包,本地仓库没有,默认去私服下载。私服可以在互联网内也可以在局域网内。

PS:有时候我们也会把远程仓库默认叫为私服Maven的仓库总体还是分为两大类的(本地仓库、远程仓库)。

   2. 中央仓库:在Maven软件中内置一个私服地址repo1.maven.org/maven2 ,它是中央仓库,服务于整个互联网(全球唯一的),它是由Maven团队自己维护,里面存储了大部分开源的jar包,它包含了世界上大部分流行的开源项目构件。

私服的作用:

  1. 保存具有版权的资源,包含购买或自主研发的jar
    1. 中央仓库中的jar都是开源的,不能存储具有版权的资源
  2. 一定范围内共享资源,仅对内部开放,不对外共享

Maven仓库.png

image.png

小结:

当本地仓库没有所需要的jar包时,会先访问远程仓库(如果没有搭建远程仓库的话,就直接去访问中央仓库),如果远程仓库没有的话,再去中央仓库下载。

远程仓库的好处:
1. 提高下载效率( 因为中央仓库是国外的。国内要去下载国外资源是很慢的。可以提前在远程仓库下载好,之后让本地仓库访问就很快了)。
2. 可以在自己的远程仓库里添加自己的jar包

2. Maven的作用

  1. Maven的依赖管理

Maven的一个核心特性就是 依赖管理。传统的WEB项目中,我们必须将工程所依赖的jar包复制到工程中,导致了工程变得很大。然而Maven工程中不直接将jar包导入到工程中,而是通过在pom.xml文件中添加所需jar包的坐标,这样就很好的避免了jar包被直接引入进来,在需要用到jar包的时候,只要查找pom.xml文件,再通过pom.xml文件中的坐标,到一个专门用于”存放jar包的仓库”(Maven仓库)中根据坐标从而找到这些jar包,再把这些jar包拿去运行即可。

  1. 项目的一键构建

我们的项目,往往都要经历编译、测试、运行、打包、安装,部署等一系列过程。

那么,什么是构建呢?
构建指的是:项目从编译、测试、运行、打包、安装,部署整个过程都交给Maven进行管理,这个过程称为构建。
那么,什么又是一键构建呢?
一键构建指的是:整个构建过程,使用Maven一个命令可以轻松完成整个工作。

Maven的作用简单小结

  • 项目构建提供标准的、跨平台的自动化项目构建方式
  • 依赖管理方便快捷的管理项目依赖的资源(jar包),避免资源间的版本冲突问题(就是管理jar包
  • 依赖指当前项目运行所需的jar包,一个项目可以设置多个依赖。
  1. Maven规范化构建流程如下:

image.png

3. Maven工程的目录结构

由于早期大家建立目录非常随意,导致Maven设置了一个统一的开发结构。

  • 统一开发结构提供标准的、统一的项目结构

image.png

作为一个Maven的Web工程文件,它的src目录和pom.xml是必备的。

进入src目录后,我们发现它里面的目录结构如下:

image.png


image.png

src/main/java —— 存放项目的.java文件
src/main/resources —— 存放项目资源文件,如spring, hibernate配置文件
src/test/java —— 存放所有单元测试.java文件,如JUnit测试类
src/test/resources —— 测试资源文件
target —— 项目输出位置,编译后的.class文件会输出到此目录
pom.xml —— maven项目核心配置文件

  • Java工程结构与Web工程结构的区别:

image.png

注意:如果是普通的java项目,那么就没有webapp目录。

4. Maven常用命令(了解)

我们可以在cmd中通过一系列的maven命令来对我们的Maven项目文件进行编译、测试、运行、打包、安装、部署。

  1. compile compile是maven工程的 编译命令 ,作用是 将src/main/java下的文件编译为.class文件输出到target目录下。Ctrl + R输入cmd进入命令状态,执行mvn compile,即可生成.class文件

  2. test test是maven工程的 测试命令 mvn test,会 执行src/test/java下的单元测试类。
    cmd执行mvn test执行src/test/java下单元测试类

  3. clean clean是maven工程的 清理命令,执行clean会 删除target目录及内容

  4. package package是maven工程的 打包命令对于java工程执行package打成jar包,对于web工程打成war包。

  5. install install是maven工程的 安装命令,执行install 将maven打成jar包 或war包发布到本地仓库

  6. 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>

image.png

2. 坐标的来源方式

  1. 可以从网上搜索(去 Maven的坐标库中(mvnrepository.com )查询并复制坐标)
  2. 先从中央仓库中把需要的jar包全部下载下来,之后再利用快捷键(IDEA:Alt + insert 插入Dependency,然后输入要导入的jar包的关键词)导入

3. 依赖范围

下面还有一个依赖范围,但它们两个是一样的。一个详,一个略。

A依赖于B,需要在A的pom.xml文件中添加B的坐标,添加坐标时需要指定依赖范围。 依赖范围包括:

  1. compile编译范围**指A在编译时依赖B,此范围为默认依赖范围**。编译范围的依赖会用在编译、测试、运行,由于运行时需要所以编译范围的依赖会被打包。

  2. providedprovided依赖只有在当JDK或者一个容器已提供该依赖之后才使用。provided依赖在编译和测试时需要,在运行时不需要,比如:servlet api被tomcat容器提供。

  3. runtime:runtime依赖在运行和测试系统的时候需要,但在编译的时候不需要。比如:jdbc的驱动包。由于运行时需要所以runtime范围的依赖会被打包。

  4. test:test范围依赖在编译和运行时都不需要,它们只有在测试编译和测试运行阶段可用,比如:junit。由于运行时不需要所以test范围依赖不会被打包。

  5. system:system范围依赖与provided类似,但是你必须显式的提供一个对于本地系统中JAR文件的路径,需要指定systemPath磁盘路径,system依赖不推荐使用。

image.png

在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包,一个项目可以设置多个依赖。

格式:

image.png

2. 依赖传递

依赖具有传递性

  • 直接依赖:在当前项目中通过依赖配置建立的依赖关系
  • 间接依赖:被资源的资源如果依赖其他资源,当前项目间接依赖其他资源

没有说谁是直接依赖于谁 or 谁间接依赖于谁的。这是一个相对概念

image.png

依赖传递的冲突问题

  • 路径优先:当依赖中出现相同的资源时,层级越深,优先级越低,层级越浅,优先级越高就近原则
  • 声明优先:当资源在相同层级被依赖时,配置顺序靠前的覆盖配置顺序靠后的先来后到
  • 特殊优先:当同级配置了相同资源的不同版本,后配置的覆盖先配置的同名覆盖原则

依赖冲突描述:

我们根据某个项目为根,对他所依赖的资源进行深度的标注。如:直接依赖称为一度资源,直接依赖的直接依赖称为二度资源...
当出现冲突的时候,一度的覆盖二度的(层级越深,优先级越低 => 路径优先)。
当遇到相同层级的看配置的顺序是否靠前(配置顺序靠前的覆盖配置顺序靠后的 => 声明优先)。
当同个项目里配置相同资源时,后配置的覆盖先配置的。

image.png

3. 可选依赖

可选依赖指:对外隐藏当前所依赖的资源——不透明(该依赖能被使用)别人不想让你看到他在干嘛

在依赖里添加:true (默认是false) 即可

PS:true 是添加在自己开发的工程中的(即 它无法隐藏别人项目里的依赖资源)。如果想去掉别的jar包里的依赖得使用

image.png

4. 排除依赖

排除依赖指:主动断开依赖的资源,被排除的资源无需指定版本——不需要(该依赖不能被使用)你不想使用这个依赖资源

image.png

排除依赖和可选依赖是一样的作用?❌🙅❌

**`可选依赖是私房钱,控制别人能不能看到你用什么。

排除依赖是主动的断开间接依赖的资源。`**

5. 依赖范围

  • 依赖的jar默认情况可以在任何地方使用。也可以通过scope标签设定其作用范围

  • 作用范围

1、主程序范围有效(main文件夹范围内)
2、测试程序范围有效(test文件夹范围内)
3、是否参与包(package指令范围内)

image.png

为什么provided不参与打包?

假设程序中用到了servlet3.0,然后你把这个3.0的jar包打包到war包里了,并且上传到服务器里了。然后tomcat服务器也有一个servlet API。此时就有可能产生冲突!(如果tomcat服务器的servlet与你项目中的servlet的版本号一致的话,没事。但如果不一样就会报错。=> 你的3.0会先加载,但tomcat不支持,这就会报错)所以我们要将servlet的依赖范围定义为:provided

为什么JDBC驱动包的依赖范围要设置成runtime?

因为JDBC是由sun公司提供的,这代表着Java内嵌了该接口了。即使你不导包也没事,只不过在运行的时候要去找具体的实现类罢了。因此将它的依赖范围设置为runtime

依赖范围具有传递性(了解即可)

带有依赖范围的资源在进行传递时,作用范围将受到影响

image.png

5、生命周期与插件

1. 项目构建生命周期

Maven构建生命周期描述的是一次构建过程经历了多少个事件

image.png

  • Maven对项目构建的生命周期划分为3套
    • clean:清理工作
    • default:核心工作,例如编译,测试,打包,部署等
    • site:产生报告,发布站点等

1、clean生命周期 image.png

2、default生命周期 image.png

3、site生命周期 image.png

生命周期控制的是:在进行构建任务的时候执行的过程有哪些。每个过程都有一件事。 那么这些事情是谁在做呢?——插件Plugin

2. 插件

插件与生命周期内的阶段绑定在一起,在执行到对应生命周期时执行对应的插件功能

默认maven在各个生命周期上绑定有预设的功能
通过插件可以自定义其他功能

image.png

小结:

生命周期:运行的阶段 Phase
插件:为了支持生命周期的那些事(设置)