初学J2EE时都会学习Maven,但工作后未必需要自己去维护依赖,导致对Maven的认知还仅限于追加
dependency
标签。工作几年后再系统性地回顾Maven,发现有些知识点至关重要,它们能帮助自己维护依赖时做到有的放矢。
依赖关系
引入依赖前,我们需要清楚应该采用何种依赖关系,虽然大部分依赖的scope
都会设置为complie
,但还有一些依赖需要设置为其它类型,一旦设置错误可能会出现BUG。举例来说,如果servlet-api
的scope
是complie
,那么servlet-api
就会被打到项目的jar里,进而导致与Tomcat
内置的servlet-api
产生冲突。
Maven定义了几种依赖关系,分别是compile
、test
、runtime
、provided
scope | 说明 | 示例 |
---|---|---|
compile | 编译时需要用到该jar包(默认) | commons-logging |
test | 编译Test时需要用到该jar包 | junit |
runtime | 编译时不需要,但运行时需要用到 | mysql(mysql驱动在编译时并不需要) |
provided | 编译时需要用到,但运行时由JDK或某个服务器提供 | servlet-api(Servlet服务器内置了相关的jar,所以运行时不需要,但是写servlet时需要继承HttpServlet,所以编译时需要) |
SNAPSHOT
对于某个依赖,Maven只需要3个变量即可唯一确定某个jar包:
groupId:属于组织的名称,类似Java的包名
artifactId:该jar包自身的名称,类似Java的类名
version:该jar包的版本
通过上述3个变量,即可唯一确定某个jar包。Maven通过对jar包进行PGP签名确保任何一个jar包一经发布就无法修改,修改已发布jar包的唯一方法是发布一个新版本。因此,某个jar包一旦被Maven下载过,即可永久地安全缓存在本地。
但是对于处于开发中的依赖,不可能每次修改jar都发布一个新版本,所以需要一个机制来实现不用发布新版本,Maven也能拉取到依赖的最新版本,这个机制就是SNAPSHOT(快照),在<version>
中以-SNAPSHOT
结尾的版本号会被Maven视为开发版本,开发版本每次都会重复下载。
依赖管理
引入依赖时可能需要考虑一些额外情况,此时就要用到<dependency>
下的一些子标签。
exclusions
实际项目中会引入大量的依赖,极有可能出现重复依赖的情况,例如A依赖C,B也依赖C,这两个C也许版本并不相同,此时就需要在A或B的<dependency>
中声明<exclusions>
来排除掉依赖C。
除了避免重复依赖的问题,<exclusions>
的意义还在于:我们想要自己引入某个依赖B,但是依赖A本身也引入了B,这就导致B被依赖传递到项目中了,我们不想要这个被传递过来的B,那么就需要在A中<exclusions>
掉B,然后自己声明一个B来引入。
optional
<optional>true</optional>
表示这个依赖是可选的,也就是说,它不会传递给依赖本项目的其他项目,这样可以避免不必要的依赖传递和冲突。举例来说,如果项目A使用的日志实现框架是log4j,但是依赖A的项目B想用logback,那么A就应该把自己的log4j设置为<optional>true</optional>
,这样B在引入A时,就不会把log4j也引入了。