Java的包原理
- JVM的工作被设计地相当简单:
- 执行一个类的字节码
- 假如这个过程中碰到了了新的类,加载它
- 那么,去哪⾥里里加载这些类呢?
- 在类路径(ClassPath)中挨个找,如果是文件夹就继续挨个找下去,如果碰到的是jar包就解压缩出来看看,能不能找到
类路径
- 在哪⾥里里可以找到类
- classpath/-cp
- 类的全限定类名(⽬目录层级)唯⼀一确定了了⼀一个类
- 包就是把许多类放在⼀一起打的压缩包,jar包就是一堆类的集合
jar包什么时候下载
- 按需下载,什么时候需要什么时候下载,比如compile需要就compile的时候下载,test的时候需要就test的时候下载
传递性依赖
- 你依赖的类还依赖了了别的类
- 如果两个包里都有github.com.a这个类,那么谁在前面最后调用谁,
- 和命令行执行顺序一样,恐怖的点是同名但是代码不一样
Classpath hell
- 全限定类名是类的唯⼀一标识
- 当多个同名类同时出现在Classpath中,就是噩梦的开始
什么是包管理
- 你要使⽤用⼀一些第三⽅方类,总要告诉JVM从哪⾥里里找吧?
- 包管理理的本质就是告诉JVM如何找到所需的第三⽅方类库
- 以及成功地解决其中的冲突问题
在没有maven的年代
- 手动管理写命令编译,黑暗岁月
启蒙时代
- Apache Ant
- 手动下载jar包,放在⼀个目录中
- 写XML配置,指定编译的源代码⽬目录、依赖的jar包、输出目录等
- 缺点
- 每个⼈人都要⾃自⼰己造⼀一套轮⼦子
- 依赖的第三⽅类库都需要手动下载,费时费⼒
- 假如你的应⽤依赖了了一万个第三方的类库呢?
- 没有解决Classpath地狱的问题
Maven——划时代的包管理理
- Convention over configuration
- 约定优于配置
- 必须强调,Maven远远不不⽌是包管理工具
- Maven的中央仓库
- 按照⼀定的约定存储包
- Maven的本地仓库
- 默认位于~/.m2
- 下载的第三⽅包放在这⾥进行缓存
maven-划时代的包管理工具
- maven的包,按照约定为所有的包编号方便检索
- 约定了三个要素,groupId,artifactId,version
- groupId有点像一个组织,所有的组织的包都放在一起
- artifactId,组织下不同的功能,比如有仓库,订单,购物车,对应不同的包,
- 包有不同版本version,一旦发布了无法撤销只能升级
- maven的包管理完爆隔壁go语言的15条街
- 根据pom将传递性依赖一个完整的树下载好
- 默认情况下maven,只会下载字节码包,需要看源代码就店家download source
- 语义化版本,版本号x.y.z,第一个x是主版本号,第二个y是次版本号,第三个z是修订号
- snapshot,对于频繁变更,不稳定的版本,只用于两个团队快速开发,正式上线之后要变成一个正式版本
- 一般也就公司内部有snapshot库,正式线上环境不会放
- RC是release candidate准备发布版,M代表里程碑milestone 版本
实战解决包冲突
-
包冲突异常的常见几种表现
- AbstractMethodError
- NoClassDefFoundError
- ClassNotFoundException
- LinkageError
-
产生包冲突的原因
- 传递性依赖的自动管理
- 原则:绝对不允许最终的classpath出现同名不同版本的jar包
- 依赖冲突的解决
- 原则:最近的胜出 2.png
- 依赖的scope
解决办法
- 人肉解决
maven dependency:tree查看依赖,也可以重定向到文件中maven dependency:tree > d.txt
- 通过pom找到库的github地址,然后通过tag去进行切换,找到两个版本的区别,定位问题,这个步骤非常耗费精力
- 解决办法1,直接强行依赖版本
- 解决方案2
- 解决方案3,使用插件maven helper
- 相同距离谁靠前谁赢
Maven的其他知识
- scope,最重要的scope有两个compile和test
- test就表示这个库的作用范围只在test中,compile表示在compile和test中都有效
- provided表示只在编译的时候有效,运行的时候就没有效果了,ide会编译和运行你的代码
- 因此provided可以成功编译,但是不能够成功运行
maven相关书籍
- maven 实战
- pom就是project object model,项目说明书
- pom字段解释,properties定义了属性,scm,source control management,源代码管理,profile指定环境