一、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的本地仓库

    • 默认位于~/.m2
    • 下载的第三方包在这里进行缓存

    • Maven的包

  • 按照约定为所有的包编号,方便检索

  • groupId/artifactId/version
    • 扩展:语义化版本
  • SNAPSHOT快照版本

三、包冲突及解决

1. 传递性依赖的自动管理

  • 原则:绝对不允许最终的classpath中出现同名不同版本的jar包(会选在前面的那一个)
    • Maven是将包按名字管理的(groupId/artifactId/version)

2. 依赖冲突的解决

  • Maven的原则:(离你的项目)最近的包胜出

image.png

  • 如图不管哪个C库版本号高,都是下面那个路径短的胜出
  • 这个原则大部分时候都是有效的
  • 可以用mvn dependency:tree查看依赖树
  • 有时候还是需要人工介入解决:
      1. 直接在项目里引入C:0.2版本(pom.xml)
      1. 手动强行排除D依赖的C依赖(pom.xml )
  • 距离一样时,谁靠前谁赢
    image.png

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),项目的说明书