一、Java的包原理
什么是包
- JVM的工作被设计得相当简单
- 执行一个类的字节码
- 假如这个过程中碰到了新的类,加载它
- 那么,去哪里加载这些类?
类路径 classpath
- 在哪里可以找到类
- -classpath/-cp
- 类的全限定类名(目录层级)唯一确定了一个类
- 包就是把许多类放在一起打的压缩包
- 传递性依赖
- 你的依赖还依赖了别的类
- classpath hell
- 全限定类名是类的唯一标识
- 当多个同名类同时出现在classpath中,就是cp hell
- 手动管理jar包是十分痛苦的,所以需要Maven进行包管理
没有Maven时
- 需要手动写命令编译运行,需要手动 -cp 指定classpath
- Apache Ant
- 手动下jar包,放在一个目录
- 写XML配置,指定编译的源代码目录、依赖的jar包、输出目录等
- 每个人都要自己造一套轮子,第三方库要手动下载,没有解决cp hell问题
二、Maven包管理
划时代的包管理
- Maven哲学:约定优于配置(Convention over configuration)
- 必须强调,Maven远不止是包管理工具
- Maven的中央仓库
- 按照一定的约定存储包
Maven的本地仓库
按照约定为所有的包编号,方便检索
- groupId/artifactId/version
- 扩展:语义化版本
- SNAPSHOT快照版本
三、包冲突及解决
1. 传递性依赖的自动管理
- 原则:绝对不允许最终的classpath中出现同名不同版本的jar包(会选在前面的那一个)
- Maven是将包按名字管理的(groupId/artifactId/version)
2. 依赖冲突的解决
- Maven的原则:(离你的项目)最近的包胜出
- 如图不管哪个C库版本号高,都是下面那个路径短的胜出
- 这个原则大部分时候都是有效的
- 可以用
mvn dependency:tree
查看依赖树 - 有时候还是需要人工介入解决:
- 直接在项目里引入C:0.2版本(pom.xml)
- 手动强行排除D依赖的C依赖(pom.xml
)
- 手动强行排除D依赖的C依赖(pom.xml
- 距离一样时,谁靠前谁赢
3. 依赖的scope
- 最重要的scope有:
<scope>compile<scope>
<scope>test<scope>
:只有在src/test环境才用到,在src/main中无法使用,不会发布出去
- 其他常见scope有
<scope>provided<scope>
:只使用这个库去编译,运行的时候不添加到classpath- 运行时环境有提供时使用
4.包冲突经常导致以下异常
- AbstractMethodError
- NoClassDefFoundError
- ClassNotFoundException
- LinkageError
四、Maven——自动化构建工具
- 《Maven实战》
- 值得看的章节:1,3和4(可以看,别用它的代码)、5-8(精华)
- 基本概念:坐标和依赖/生命周期/仓库/聚合和继承
- 使用Maven进行测试
- 如果需要开发插件的话:
- Maven的插件
- pom.xml(project object model),项目的说明书