Java的包管理与Maven

Jan 13, 2020


什么是包?

JVM的工作被设计的相当简单:

  • 执行一个类的字节码
  • 假如这个过程中碰到了新类,加载它

那么去哪加载这些类呢?可以通过Classpath来寻找这些类,如果是目录,就直接找,如果是jar文件,就把文件解压缩然后再找。

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

那么这些jar包就是一堆类的集合,是把许多类放在一起打的压缩包

什么是包管理?

你要使用一些第三方类,需要告诉JVM去哪里找

包管理的本质就是告诉JVM如何找到所需的第三方类库,以及成功的解决其中的冲突问题。

Maven

在没有Maven的年代,需要手动写命令编译运行。后来有了Apache Ant。

Maven是一个包管理工具和自动化构建工具,它的一个原则是:Convention over configuration(约定优于配置)。

如果你需要使用一个第三方类库,那么需要在pom.xml加入该依赖,这样就能自动从Maven中央仓库下载。

Maven有一套中央仓库,按照一定的约定把这些包存储起来。除了中央仓库,Maven的本地仓库默认位于~/.m2,默认从中央仓库下载缓存到这个目录。

Maven对包进行了抽象,对所有的包添加了3个属性:groupIdartifaactIdversion,可以根据这个规则去找对应的包。

语义化版本 2.0.0:https://semver.org/lang/zh-CN/

包冲突

Maven自动解决了传递性依赖。

比如当项目所引用的库的传递性依赖库有相同时,就会发生包冲突。

包冲突的表现有:

  • AbstractMethodError
  • NotClassDefError
  • ClassNotFoundException
  • LinkageError

Maven对传递性依赖的自动管理有个原则:

  • 绝对不允许最终的classpath出现同名不同版本的jar包

那么对于上面举的例子,就需要删除一个包,

对于包冲突,Maven的解决原则是:

  • 离项目最近的包胜出

推荐一个IDEA插件:Maven Helper,可以帮助你解决包冲突

Maven依赖scope

指定依赖只在某个地方有效,比如只在test中。

常见的scope有:

  • <scope>compile</scope>
  • <scope>test</scope>

2个pom.xml例子

https://github.com/alibaba/fastjson/blob/master/pom.xml

https://github.com/google/guava/blob/master/pom.xml