`
leonzhx
  • 浏览: 767985 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

关于 Maven的传递依赖的理解

阅读更多

今天又回顾了一下 《Maven in Action》的读书笔记第五章 : http://seanzhou.iteye.com/admin/blogs/1290558。再次看到这张Maven 传递依赖的表格:

 

 

假设 A 依赖 B B 依赖 C ,我们称 A B 是第一直接依赖, B C 是第二直接依赖, A C 是传递依赖。下表显示了三者的关系:

第一          第二

compile

test

provided

runtime

compile

compile

-

-

runtime

test

test

-

-

test

provided

provided

-

provided

provided

runtime

runtime

-

-

runtime

 

 

 

当时就对这张表格有点一知半解,向同事和老鸟请教,大都无法对其进行解释,甚至在某次技术会议现场遇到《Maven in action》的作者Juven,向其讨教,他也一时无法解释。

    如今在Maven项目上实践了这么久,又对这张表有了新的理解。首先,我觉得所谓A对B有依赖,是指A对B的artifact有依赖,也就是依赖的是B的binary。其次依赖范围决定了A对B在什么时间段具有依赖。一共有三种时间段:a)在编译源代码时 b) 在编译测试代码及运行测试用例时  c)  在运行时

    四种依赖范围分别表示了在不同的时间段具有依赖:

1)compile: a) & b) & c)

2)test : b)

3)provided: a) & b)

4) runtime: c)

 

可见test与runtime是最弱的依赖,其次是provided,然后再是compile。下面我们来看传递依赖,我们换个角度,先不从依赖范围来看传递依赖,而是从依赖的时间段来看传递依赖。

 

                           第二

第一

            a)                        b)                        c)           
              a)             -             -             -
              b)             -             -             b)
              c)             -             -             c)

 

解释一下,第一列表示A对B的依赖时间段,第二列表示B对C的依赖时间段。首先,如果 A对B是在编译时依赖,那A对C一定没有依赖,因为编译源代码时只需要B的binary即可通过编译,B的依赖都不会需要。所以第二行都为没有依赖。其次如果B对C为编译时依赖,因为之前说过A对B的依赖都是指A对B的binary的依赖,B无需重新编译源代码,所以第二列都为没有依赖。同样的如果B对C为编译和运行测试代码时依赖,因为无论A只对B的binary有依赖(主代码),与B的测试代码没有关系,所以第三列也都为没有依赖。所以现在只剩下表格中最后一列的最后两格需要解释了:

    1. A对B在编译及执行测试代码时有依赖,而B对C在主代码运行时有依赖

     对编译A的测试代码来说,A只需要B的binary,一定对C没有依赖,但对执行A的测试代码来说,执行时需要调用到B代码,而这时对B来说这是它的主代码的运行时,它对C是有依赖的。所以A对C也就有了依赖(A运行测试代码时对C有依赖)

     2. A对B主代码运行时有依赖,而B对C在主代码运行时有依赖

     同理,在运行A的主代码时,A需要调用B的主代码,而这时也是B的主代码的运行时,所以B需要调用C。所以A对C也有了依赖(A运行主代码时对C有依赖)。

 

    下面我们来看依赖范围,我们将依赖范围的这张传递依赖表转换成,依赖时间段的传递依赖表:

第一         第二

a)&b)&c) 

b)

a)&b)

c)

     a)&b)&c)

b)&c)

-

b)&c) 

         b)

b)

-

-

b)

      a)&b)

b)

-

b)

         c)

c)

-

-

c)

 

我们来对比一下原表:

    1)  compile + compile --> compile, 而我们这里推出的是 b) & c),因为没有一个特定范围对应 b) & c)所以用compile来代替是合理的。

    2) compile + provided -->无依赖也是合理的,但有一点必须注意,provided这个范围是比较特殊的,它并不是说在运行时没有依赖,而是说运行时的依赖会由运行环境提供,这点对传递依赖很重要。对于compile + provided的情况,我们必须保证在A的测试环境中C已经存在了 ,不然是会有问题的。因为B假定C在B的运行时已经存在了。比如说 C是servelt api,在deploy B到一个servlet container中时,C会由container提供,但在A的测试和运行环境中,必须也保证C已经存在(特别是A的测试环境)不然就有可能出现runtime exception。

    3) compile + runtime --> runtime, 这点有些不合理,这会导致,在A的测试代码运行时,它调用B,而B需要调用C,这时会出现runtime excpetion。(所以我推导出的是 b) & c) ) 我持着怀疑的态度特地在Maven 3.03上验证了一下,确实compile + runtime --> runtime。所以这里我们就要特别小心了,如果A的测试代码运行时,有可能需要间接调用到C,你需要显示声明C为A的compile依赖。 (因为默认是runtime依赖,加上test依赖就是compile依赖)

    4)provided + compile --> provided , 这个是很有问题的,首先, A对C在编译时肯定是不需要的(有B的binary就足够编译了)。所以我们推出的是c),也就是只在测试时需要(运行测试代码时需要)。但有一点我们需要多思考一下的,A对B是provided依赖,表明在A的主代码运行时B已经被环境提供了,A在运行时是依赖B的,而B对C是compile依赖,也就是B在运行时对C有依赖,也就是说A在运行时其实是间接依赖C的,而如果A的运行时环境提供了B,没理由不提供B的运行时依赖C, 所以这里最后得到的是provided(因为test无法表示运行时的依赖性)。

    5)provided + provided --> provided,虽然我推导出的是无依赖,但由于provided的特殊性,provided并不能简单用 a) & b)来表示,其实在运行时是有依赖的,只是依赖由环境提供。首先A对C肯定在编译时是没有依赖的,但在运行测试代码时是有依赖的,因为B对C是provided依赖,也就是说C由B的运行环境提供,所以在A的测试环境需要提供C。和上节同样的道理,A的运行环境提供了B,没道理不提供B的运行时依赖C(B项目也假定了在其运行时会由环境提供C)所以是provided依赖。

    6) provided + runtime --> provided,这点其实得provided + compile --> provided同理。

 

 

   OK, 这样原先的大部分疑惑都已经解决了,回过头来看一下,主要是provided这个范围比较搞,它并不表示在运行时没有依赖,只是表明依赖会由运行时环境提供,但问题是如何预先知道项目的运行时环境,项目的运行时环境是会变化的。因为如果A在运行时依赖B,A的运行时环境就成了B的运行时环境可能会与原先单独运行B的环境不同。感觉Maven的这一设计有些许问题。

 

3
1
分享到:
评论
5 楼 心存高远 2018-01-17  
谢谢作者分享,刚好看到这里不太明白,现在茅塞顿开。不过runtime依赖范围其实对测试classpaths也是有效的。官网原文:runtime,This scope indicates that the dependency is not required for compilation, but is for execution. It is in the runtime and test classpaths, but not the compile classpath.
4 楼 sxlkk 2015-12-22  
851228082 写道
甚至在某次技术会议现场遇到《Maven in action》的作者Juven,向其讨教,他也一时无法解释。

作者自己都不知道?!!!  我也是醉了

哈哈
3 楼 851228082 2015-10-27  
甚至在某次技术会议现场遇到《Maven in action》的作者Juven,向其讨教,他也一时无法解释。

作者自己都不知道?!!!  我也是醉了
2 楼 leonzhx 2013-11-14  
谢谢你提供的链接,刚刚看了一下,你好像说反了,非但compile+provided ==>无依赖,连provided + provided ==>无依赖了。
1 楼 无红墙 2013-11-13  
这张依赖传递的表跟maven官网 http://maven.apache.org/guides/introduction/introduction-to-dependency-mechanism.html#Dependency_Scope 上的好像不一样。

compile+provided => provided,而非无依赖

相关推荐

Global site tag (gtag.js) - Google Analytics