前两天在一个技术群,有人还在问maven中groupId、artifactId、version这些关键字的含义是什么,于是,我觉得还是很有必要来聊聊Maven中的这些核心概念。

成功不是将来才有的,而是从决定去做的那一刻起,持续累积而成。

今天我们来学习Maven中的核心概念。了解了这些核心概念后,我们后面就可以更深层次地学习和使用Maven。

坐标

坐标的概念

来自百度百科

能够确定一个点在空间的位置的一个或一组数,叫做这个点的坐标。通常由这个点到垂直相交的若干条固定的直线的距离来表示 。这些直线叫做坐标轴。坐标轴的数目在平面上为2(x,y),在空间里为3(x,y,z)。

其实就是可以标识平面中或空间里唯一的一个点。

Maven中的坐标

Maven其中一个核心的作用就是管理项目的依赖,引入我们所需的各种jar包等。为了能自动化地解析任何一个Java构件,Maven必须将这些Jar包或者其他资源进行唯一标识,这是管理项目的依赖的基础,也就是我们要说的坐标。包括我们自己开发的项目,也是要通过坐标进行唯一标识的,这样才能才其它项目中进行依赖引用。

案例

依赖时候:比如下面我们依赖junit的jar包。

<!-- pom.xml中 -->
<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>3.8.1</version><scope>test</scope>
</dependency>

项目中定义我们的项目将打成jar或者war包。

<?xml version="1.0" encoding="UTF-8"?>
<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.tian</groupId><artifactId>maven-demo</artifactId><version>1.0-SNAPSHOT</version><!-- 默认是jar --><packaging>jar</packaging>
</project>

最后打出来的jar或war的形式的形式:

artifactid-version.jar
artifactid-version.war

packaging 标签默认是jar,所以通常我们在没有指定打成jar包还是war的时候,最终打成的就是jar包。

Maven坐标的组成

  • 「groupId」组织标识(包名)。定义当前Maven项目隶属的实际项目。首先,Maven项目和实际项目不一定是一对一的关系。比如SpringFrameWork这一实际项目,其对应的Maven项目会有很多,如spring-core,spring-context等。这是由于Maven中模块的概念,因此,一个实际项目往往会被划分成很多模块。其次,groupId不应该对应项目隶属的组织或公司。原因很简单,一个组织下会有很多实际项目,如果groupId只定义到组织级别,而后面我们会看到,artifactId只能定义Maven项目(模块),那么实际项目这个层次将难以定义。最后,groupId的表示方式与Java包名的表达方式类似,通常与域名反向一一对应。上例中,groupId为junit,是不是感觉很特殊,这样也是可以的,因为全世界就这么个junit,它也没有很多分支。
  • 「artifactId」项目名称。该元素定义当前实际项目中的一个Maven项目(模块),推荐的做法是使用实际项目名称作为artifactId的前缀。比如上例中的junit,junit就是实际的项目名称,方便而且直观。在默认情况下,maven生成的构件,会以artifactId作为文件头,如junit-3.8.1.jar,使用实际项目名称作为前缀,就能方便的从本地仓库找到某个项目的构件。
  • 「version」项目的当前版本或者我们要依赖jar的版本。该元素定义了使用构件的版本,如上例中junit的版本是3.8.1,你也可以改为4.0表示使用4.0版本的junit。
  • 「packaging」项目的打包方式,最为常见的jar和war两种,默认是jar。定义Maven项目打包的方式,使用构件的什么包。首先,打包方式通常与所生成构件的文件扩展名对应,如上例中没有packaging,则默认为jar包,最终的文件名为junit-3.8.1.jar。也可以打包成war等。
  • 「classifier」 该元素用来帮助定义构建输出的一些附件。附属构件与主构件对应,如上例中的主构件为junit-3.8.1.jar,该项目可能还会通过一些插件生成如junit-3.8.1-javadoc.jar,junit-3.8.1-sources.jar, 这样附属构件也就拥有了自己唯一的坐标。

上述5个元素中,groupId、artifactId、version是必须定义的,packaging是可选的(默认为jar),而classfier是不能直接定义的,需要结合插件使用。

Maven为什么使用坐标呢?

  • Maven世界里拥有大量构建,我们需要找一个用来唯一标识一个构建的统一规范。
  • 拥有了统一规范,就可以把查找工作交给机器。

maven依赖管理

依赖

依赖通常表现为:我需要你的东西,就像情侣之间相互依赖,夫妻之间相互依赖,人依赖于水,人依赖于粮食等。

在Maven中则表现为:项目中用到b.jar包的每个类,此时的项目就依赖b.jar。

复杂点关系就是多层依赖:a.jar包依赖b.jar包,还有可能b.jar包依赖c.jar。这种现象也可以称之为依赖传递性。

我们的项目间接性的依赖了b.jar。

依赖配置

Maven中依赖配置案例如下:

<!--添加依赖配置-->
<dependencies><!--项目要使用到junit的jar包,所以在这里添加junit的jar包的依赖--><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.9</version><scope>test</scope></dependency><!--项目要使用到Hello的jar包,所以在这里添加Hello的jar包的依赖--><dependency><groupId>com.tian.maven</groupId><artifactId>user-service</artifactId><version>0.0.1-SNAPSHOT</version><scope>compile</scope><!-- 依赖范围--></dependency>
</dependencies>

依赖范围

所谓的依赖范围就是指我们在什么需要依赖的jar。有的是在编译的时候就需要,有的是测试的时候需要等。

依赖范围scope有以下6种:

  • 「compile」 默认编译依赖范围。对于编译,测试,运行三种classpath都有效。即在编译、测试和运行的时候都要使用该依赖jar包;
  • 「test」测试依赖范围。只对于测试classpath有效。而在编译和运行项目时无法使用此类依赖,典型的是JUnit,它只用于编译测试代码和运行测试代码的时候才需要;
  • 「provided」已提供依赖范围。对于编译,测试的classpath都有效,但对于运行无效。因为由容器已经提供,例如servlet-api.jar,这个在编译和测试的时候需要用到,但是在运行的时候,web容器已经提供了,就不需要maven帮忙引入了。
  • 「runtime」运行时依赖范围,使用此依赖范围的maven依赖,对于编译测试、运行测试和运行项目的classpath有效,但在编译主代码时无效,比如jdbc驱动实现,运行的时候才需要具体的jdbc驱动实现。
  • 「system」系统依赖范围,使用system范围的依赖时必须通过systemPath元素显示的指定依赖文件的路径,不依赖Maven仓库解析,所以可能会造成建构的不可移植(即就是在你的电脑上可能没问题,但是到别人电脑上那就说不清楚了),有点类似provided ,注意这个system谨慎使用。
<systemPath>${java.home}/lib/rt.jar</systemPath>
  • 「import」仅pom在本节中的类型依赖项上支持此作用域。它指示依赖关系将被指定的pom部分中的有效依赖关系列表替换。由于已替换它们,因此范围内的依赖项import实际上不会参与限制依赖项的可传递性,在springboot和springcloud中用到的比较多。

以上六种范围中,常用的有compile、test、runtime、provided 。

依赖范围不仅可以控制与三种classpath的关系,还对传递性依赖产生影响,依赖关系图如下:

「注意」预期这应该是运行时范围,因此必须明确列出所有编译依赖项。但是,如果您依赖的库从另一个库扩展了一个类,则两者都必须在编译时可用。因此,即使编译时间相关性是可传递的,它们仍保留为编译范围。

Maven仓库管理

Maven仓库

用来统一存储所有Maven共享构建的位置,说白了就是用来存放jar包的,我们本地每次编译的时候没有对应jar包是编译通不过的,我们一个项目中是需要很多jar的依赖的,这时候就知道仓库的重要性了。

Maven仓库布局

根据Maven坐标定义每个构建在仓库中唯一存储路径,大致为:

groupId/artifactId/version/artifactId-version.packaging

本地仓库

在上一篇文章中,每个用户只有一个本地仓库,默认是在~/.m2/repository/,~代表的是用户目录 。为了便于管理,一般都会自己搞一目录,专门用来存储本地仓库内容。这样我们开发的时候,依赖那个jar就直接去我们的本地仓库repository中去查找,如果没有,我们会从中央仓库中拉取。

中央仓库

基本上保存了对外开发的所有jar包,Maven默认的远程仓库,(外国网站)URL地址:http://search.maven.org/ 。还有比如阿里的仓库,我们在开发的时候,由于网络原因,很多人都喜欢使用阿里的这个仓库:http://maven.aliyun.com 。

这时候我们本地仓库和中央仓库的关系:

私服

大部分公司都会搭建私服,私服就是一种特殊的远程仓库,它是架设在局域网内的仓库 。比如公司搭建局域网,公司也搞个仓库,然后开发人员就直接使用公司搭建的私服就行了,这样大大减少了网络开销以及开发成本(有时候外网访问很慢,会浪费大家开发时间的)。

这样开发人员每次需要每个jar包就直接从公司的私服里拉取,不需要使用外网去中央仓库里拉取了。总之节约时间和节约网络开始。并且有些企业还是不给外网的,这时候你就知道这个私服的重要性了。

增加了私服后,本地仓库+私服+中央仓库的关系图:

面试中也频繁被问:本地仓库、私服以及中央仓库是什么关系?

Maven生命周期

Maven的 生命周期:从我们的项目构建,一直到项目发布的这个过程。

每个阶段的说明:

为了完成 default 生命周期,这些阶段(包括其他未在上面罗列的生命周期阶段)将被按顺序地执行。

Maven 有以下三个标准的生命周期:

  • Clean Lifecycle 在进行真正的构建之前进行一些清理工作。
  • Default Lifecycle 构建的核心部分,编译,测试,打包,部署等等。
  • Site Lifecycle 生成项目报告,站点,发布站点。

这三个标准它们是相互独立的,你可以仅仅调用clean来清理工作目录,仅仅调用site来生成站点。当然你也可以直接运行 mvn clean install site运行所有这三套生命周期。

运行任何一个阶段的时候,它前面的所有阶段都会被运行,这也就是为什么我们运行mvn install 的时候,代码会被编译,测试,打包。此外,Maven的插件机制是完全依赖Maven的生命周期的,因此理解生命周期至关重要。

Maven插件

Maven是不做具体事情的,只是规定了生命周期的各个阶段和步骤,由集成到 Maven 中的插件完成。

  1. Maven的核心仅仅定义了抽象的生命周期,具体的任务都是交由插件完成的。
  2. 每个插件都能实现多个功能,每个功能就是一个插件目标。
  3. Maven的生命周期与插件目标相互绑定,以完成某个具体的构建任务, 例如compile就是插件maven-compiler-plugin的一个插件目标。

关于插件,这里就说个大概,后续会出一篇文章专门来说Maven插件。

排除不需要依赖

<dependency><groupId>com.tian.maven</groupId><artifactId>my-maven</artifactId><version>1.0.0</version><exclusions><exclusion><groupId>com.tian.maven</groupId><artifactId>your-maven</artifactId></exclusion></exclusions>
</dependency>

上面使用使用exclusions元素排除了my-maven->your-maven依赖的传递,也就是my-maven->your-maven不会被传递到当前项目中。

exclusions中可以有多个exclusion元素,可以排除一个或者多个依赖的传递,声明exclusion时只需要写上groupId、artifactId就可以了,version可以省略。

总结

本文讲述Maven坐标,Maven依赖管理、Maven仓库管理、Maven生命周期以及简单介绍了Maven插件。有了这些概念作为铺垫,我们就可以更深层次去体会,为什么我们在工作室这么用的。

「只要路是对的,就不怕路远。」

Maven的核心概念(五分钟快速掌握)相关推荐

  1. 理解 maven 的核心概念

    前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. 本文以类图的方式,介绍 maven 核心的 12 个概念及相互之间的关系. Table of Con ...

  2. Maven的核心概念

    Maven的核心概念 核心概念 1)POM 2)约定的目录结构. 3)坐标 4)依赖 5)仓库 6)生命周期 7)插件和目标 8)继承 9)聚合 POM Project Object Model:项目 ...

  3. markdown 本地链接_五分钟快速入门Markdown

    前言 开篇第一问,什么是markdown?我为什么选择用它而不是用word? markdown是一种极为简洁的标记语言,使用markdown可以更集中于写作内容本身而不必过分纠结于格式排版问题,可以把 ...

  4. 微信公众号消息推送【专属早安】,五分钟快速实现,不会编程也可以 【--网站已修复】

    效果演示 提前准备 申请一个微信公众号测试号.地址:测试号申请 扫码登陆注册,注册成功后就会生成微信公号的appID和appsecret.[最后步骤需要] 页面往下滑 有一个测试号二维码,[需要接收消 ...

  5. 五分钟快速过完Verilog HDL基本概念(5)数据类型

    数据类型 数据类型是用来表示数字电路中的数据存储和传送单元. Verilog HDL中共有19种数据类型:其中4个最基本的数据类型为: integer型 parameter型 reg型 wire型 其 ...

  6. 五分钟快速过完Verilog HDL基本概念(4)代码的编写标准

    每个Verilog HDL源文件中只准编写一个顶层模块,也不能把一个顶层模块分成几部分写在几个源文件中. 若一个源文件中有多个模块,则其中只能有一个顶层模块(其名与文件同名),其它为子模块:而且应在顶 ...

  7. 五分钟快速过完Verilog HDL基本概念(3)语法讲解

    Verilog HDL逻辑功能定义 1.在Verilog 模块中有3种方法可以描述电路的逻辑功能: 用assign 连续赋值语句,常用于描述组合逻辑 assign x = ( b & ~c ) ...

  8. 五分钟快速过完Verilog HDL基本概念(2)

    Verilog 用于模块的测试 如何检查上述例子其功能是否正确? 需要有测试激励信号输入到被测模块 需要记录被测模块的输出信号 需要把用功能和行为描述的Verilog模块转换为门级电路互连的电路结构( ...

  9. 五分钟快速过完Verilog HDL基本概念(1)

    Verilog既是一种行为描述的语言也是一种结构描述语言.Verilog模型可以是实际电路的不同级别的抽象.这些抽象的级别包括: 系统级(system):用高级语言结构实现设计模块的外部性能的模型. ...

  10. Spring Data JPA 五分钟快速入门和实践

    Spring Data JPA(类似于Java Web 中的 DAO) 操作声明持久层的接口(Repository) 三个核心接口: CrudRepository PagingAndSortingRe ...

最新文章

  1. java中运用label跳转
  2. linux死锁检测的一种思路【转】
  3. 惯性传感器的卡尔曼滤波
  4. 属性编辑器未在PropertyEditorManager中注册?
  5. SpringBoot 之Spring Boot Starter依赖包及作用
  6. 2013年快要过去了,为新来的2104计划
  7. ES6中的迭代器(Iterator)和生成器(Generator)(一)
  8. Python super钻石继承
  9. python学习 数据类型之序列
  10. Android入门笔记04
  11. 在计算机上最常用的英语单词,计算机常用英语单词
  12. 斐波那契数列(各种代码实现斐波那契数列)
  13. php相亲段子,个个都是老司机!NPC段子手们经典语录
  14. 思迅软锁安装配置说明
  15. layui 使用文档总结
  16. blacklist regions:NGS测序数据中的黑名单
  17. HDFS成员的工作机制
  18. 酷6网李善友主题演讲:创业与哲学
  19. 怎么压缩图片,电脑上压缩图片的方法
  20. Python学习笔记Day01--Day06

热门文章

  1. 发送需要smtp认证的邮件
  2. html5视频播放器 知乎,iPhone、iPad 如何播放网页调用优酷视频?
  3. aspf ftp_【解析】文件传输协议:FTP、TFTP、SFTP有什么区别?
  4. springmvc源码-我们自定义的参数解析器是如何放入到spring容器中的
  5. spring源码:@Bean注解解析
  6. Mybatis原理解析(二)SqlSession的创建过程
  7. 使用telnet 方式管理交换机
  8. LOJ2361「NOIP2016」组合数问题
  9. CF1042C Array Product
  10. [数据结构] 三十二叉堆