Java的包管理与Maven

前言:在Java的世界中,【包】是最基本的结构,因此包管理就是Java项目中的一件特别重要的事情。本文介绍的就是Java世界中的包管理,以及最流行的包管理工具Maven。


Java的包管理

要介绍Java的包管理,我们就要先知道什么是包:

包管理中的【包】指的是什么?

  • 首先,我要知道JVM(Java Virtual Machine,即Java虚拟机)的工作原理。实际上,JVM的工作被设计的相当简单:

    1. 执行一个类的字节码
    2. 假如这个过程中碰到了新的类,就加载它,然后执行第一个步骤
  • 那么,我们从哪儿加载这些类呢?
    答案是【class path】
    在IDEA中,我们执行了一段程序,在界面的下方,我们没有注意到的一段灰色的代码,里面就藏着classpath


    idea界面

    在这段命令中,-classpath 或者 -cp后面接的就是这段程序找包的地方。

  • 类的全限定类名(目录层级)唯一确定了一个类

  • 包,就是把许多类放在一起打的压缩包

包的传递性依赖

  • 何为传递性依赖,即:你依赖的类还依赖了别的类
  • 于是,恐怖的事情发生了:classpath hell(依赖地狱)
    • 全限定类名是类的唯一标识
    • 如果,我引用了A包和B包,B包中又引用了A包,就会出现多个同名类(A包)出现在classpath中,这就是下文即将说到的【包冲突
    • 如果出现了包冲突,默认的解法就是:优先使用classpath排在前面的包
  • pom.xml (pom,就是Project Object Model)就是一份项目的说明书,看了pom.xml就知道这个项目是如何工作的。

什么是包管理

简单来说包管理的本质就是下面三点:

  • 你要使用一些第三方类,总要告诉JVM从哪里找吧?
  • 包管理的本质就是告诉JVM如何找到所需的第三方类库
  • 以及成功的解决其中的冲突问题

Maven的包管理

Apache Maven,是一个软件(特别是Java软件)项目管理自动构建工具,由Apache软件基金会所提供。基于项目对象模型(缩写:POM)概念,Maven利用一个中央信息片断能管理一个项目的构建、报告和文档等步骤。

Maven是一个划时代的成就,必须强调,Maven远远不止是包管理工具,还是一个自动化构建工具。Java在经历了很多年的发展后,Maven的应运而生,是我们在庞大的Java项目中管理包不再是一件令人头疼的事情。

Maven —— 划时代的包管理

  • Maven的中央仓库(即远程仓库),按照一定的约定存储包,我们可以在中央仓库中,找到所有的已经发布了的包,用于我们查找及下载。
  • Maven的本地仓库,默认位于~/.m2,下载的第三方包放在这里缓存
  • 而Maven最优秀的地方就是,它规定了每一个包的命名规范,按照这种约定,我们就能方便的在中央仓库找到不同团队、不同版本的包,在项目中,也可以确定的引入我们想要引入的包。而Maven的命名规范主要是按照以下三个维度:
    • groupId / artifactId / version

groupidartifactId被统称为“坐标”是为了保证项目唯一性而提出的,如果你要把你项目弄到maven本地仓库去,你想要找到你的项目就必须根据这两个id去查找。

groupId一般分为多个段,这里我只说两段,第一段为域,第二段为公司名称。域又分为org、com、cn等等许多,其中org为非营利组织,com为商业组织。举个apache公司的tomcat项目例子:这个项目的groupId是org.apache,它的域是org(因为tomcat是非营利项目),公司名称是apache,artifactId是tomcat。

比如我创建一个项目,我一般会将groupId设置为cn.enoch,cn表示域为中国,enoch是我的名字,artifactId设置为testProj,表示你这个项目的名称是testProj,依照这个设置,你的包结构最好是cn.enoch.testPro打头的,如果有个StudentDao,它的全路径就是cn.enoch.testProj.dao.StudentDao

拓展:语义化版本

5.0.0-M1 【milestone 里程碑】
5.0.0-RC1 【Release candiate,正式版本的候选版本】
alpha:内部版本
beta:公测版本
SNAPSHOT:快照版本,用于开发联调的包

Maven 包冲突及解决

什么是包冲突

简单的来说就是因为传递性依赖导致某一个包被引入了两次,在classpath中出现了两次,从而导致我们在运行Java程序时,classpath中后出现的那次引入的包不会被引入到项目中来。

包冲突可能会出现的异常

  • AbstractMethodError
  • NoClassDefFoundError
  • ClassNotFoundException
  • LinkageError

Maven传递性依赖的自动管理:

  • 原则:绝不允许最终的classpath出现同名不同版本的jar包
  • 依赖冲突的解决原则:最近的胜出
    远,还是近?

    上图中,最终形成的classpath,【C0.2】会被舍弃,即,包冲突导致我们被迫使用了低版本的jar包

怎么解决呢?

  • 首先:需要理清项目中的依赖关系,找到哪一个依赖因为maven自动给舍弃导致的问题
  • 然后可能需要去看一下这个包的不同版本的源码,找到为什么maven自动舍弃一些包依赖后会报异常(比如上面的例子:高版本被舍弃,但是我们用到了高版本才有的方法)
  • 解决它(两种解法)
    1. 在我的项目中,直接依赖【C0.2】版本,这样maven就会选择最近的【C0.21】,即在项目pom中直接引入该版本包的dependency。
    2. 排除掉【D包】的传递性依赖,这样我们的依赖树就只有一个【C0.2】包了 。使用exclusions,排除掉D包依赖的C包。


      exclusions的用法

如果两个发生冲突的包”距离“一样呢?

距离一样,怎么办

这张图,【C0.1】和【C0.2】具体相同,那么maven为了保证classpath同名包只有一个,就会选择最先声明的包,舍弃后者(比如先依赖的A,就会选择C0.1)

Maven的其他知识

scope

  • 依赖的scope(指定依赖只在scope中有效),实现依赖的隔离
    • compile/test/provided等等
    • main 生产代码 / test 测试代码
  • 最重要的有三个:(test / compile / provided)
    • <scope>test</scope>
      只有在测试代码中(@TEST)才看得到这个包,在main里面无法使用这个包
    • <scope>compile</scope>
      在main和test都可见,即编译时候可见,运行时候可见,测试代码可见,生产代码可见
    • <scope>provided</scope>
      只在编译的时候有效,运行的时候就无效了,即只把这个包用于编译。
      • 编译:把源代码变成字节码的过程
      • 运行:jvm加载字节码并开始运行的过程
      • NoClassDefFoundError
      • tomcat
        比如你的代码经过编译以后要部署到tomcat容器中,tomcat容器会帮你添加一些第三方依赖包,为了防止包冲突,我们就需要把这些包设置成provided

Maven查看依赖树

  • mvn dependency:tree
    展示的是解决冲突后的依赖树
  • 在idea中看
  • 安装maven helper插件
    pom文件中,选择dependency analyzer --》all dependencies as tree

(完)

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,761评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,953评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,998评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,248评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,130评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,145评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,550评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,236评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,510评论 1 291
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,601评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,376评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,247评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,613评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,911评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,191评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,532评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,739评论 2 335

推荐阅读更多精彩内容