问题描述:当建一个多module的maven项目时,我们想要的效果是:

  1. 当子项目引用父项目时,我们可以根据需要引用其他子项目,而不是全部其他子项目.
  2. 当别的项目引用我们这个父项目时,应该引用了全部子项目.
    那我们如何达到这个目标.
    首先,我们知道maven的pom文件里面,如果我们想引用另一个项目就需要这样:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>4.2.5.RELEASE</version>
</dependency>

这样引用后,我们就可以从项目的Maven Dependencies里面看到引用的jar包.
而在我们开发多模块项目时,我们每个子项目都是在父项目的管理下,一般我们的子项目pom像这样继承父项目:

<parent>
    <groupId>com.xiaoyu</groupId>
    <artifactId>parent-example</artifactId>
    <version>0.0.1</version>
</parent>

因为我们的子项目肯定是需要引用别的子项目的,那我们父项目比如这样:

<modules>
    <module>child-A</module>
    <module>child-B</module>
    <module>child-C</module>
</modules>
<dependencies>
    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-A</artifactId>
        <version>0.0.1</version>
    </dependency>

    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-B</artifactId>
        <version>0.0.1</version>
    </dependency>
    
    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-C</artifactId>
        <version>0.0.1</version>
    </dependency>
</dependencies>

这时候假如我们child-A需要引入child-B,那么我们肯定会在child-A的pom里面这样写:

<parent>
    <groupId>com.xiaoyu</groupId>
    <artifactId>parent-example</artifactId>
    <version>0.0.1</version>
</parent>
 <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-B</artifactId>
        <version>0.0.1</version>
</dependency>

没问题是不是,我也觉得很ok,可是实际你会发现,child-A的Maven Dependencies里面包含了所有的子项目的jar包.这就尴尬了,我们不需要别的子项目呀.
这点怎么解决了.如果有经验的同学肯定会用这个dependencyManagement标签来解决.于是,我们修改父项目的pom文件:

<dependencyManagement>
<dependencies>
    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-A</artifactId>
        <version>0.0.1</version>
    </dependency>

    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-B</artifactId>
        <version>0.0.1</version>
    </dependency>
    
    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-C</artifactId>
        <version>0.0.1</version>
    </dependency>
</dependencies>
</dependencyManagement>

也就是用dependencyManagement把dependencies包起来,这样有啥用了.就是在我们子项目继承父项目的时候,并不会引入所有的dependency,而是子项目写了哪个就引入哪个.非常nice.
好了,这时候我们写完了parent-example多模块项目.另一个项目组需要引入这个项目,于是她们在项目里面这样:

<dependency>
    <groupId>com.xiaoyu</groupId>
    <artifactId>parent-example</artifactId>
    <version>0.0.1</version>
</dependency>

没有问题,然后她们发现,额…Maven Dependencies没有发现parent-example相关的子项目.为啥了,因为dependencyManagement,刚刚已经提到了,这个标签只会引入你写的具体的子项目.那么她们是不是要分别引入child-A,child-B,child-C?说实话,这样引入的确可以,但是假如以后我们的parent-example发展了几十个子项目,难道我们的同事要写几十个引入.不现实,也不科学.
不过我们不用dependencyManagement的话就可以成功引入,但是这样的话,parent-example内部的子项目就会引入全部其他子项目了.似乎我们陷入死循环了.
此时我也是非常的萌比啊,就这一个pom文件啊,该怎么搞,各种百度,谷歌都不行.后来也是瞎猫碰到死耗子,发现了这个标签relativePath,这个标签的意思是指定我们pom文件的位置.这一句话点醒梦中人,我们项目不一定是一个pom文件啊.我陷入死循环的原因就在于我一直认为项目里肯定是只有一个pom文件.
好了,我们现在就可以在我们parent-example在建一个文件夹otherPom,建一个新的pom文件pom1.xml.这样,我们认定父项目的pom是给外部项目引用的,pom1.xml是给子项目使用的.
于是,我们在父项目的pom里面只使用dependencies,而在pom1.xml里面使用dependencyManagement,最后我们子项目里面这样:

<parent>
    <groupId>com.xiaoyu</groupId>
    <artifactId>parent-example</artifactId>
    <version>0.0.1</version>
    <relativePath>../otherPom/pom1.xml</relativePath>
</parent>

多了个relativePath,我们就可以把内外部项目的关系给分离开.通过这样,我们子项目就可以通过pom1.xml的dependencyManagement避免引入全部子项目,而外部项目通过父项目的dependencies就可以引入所有子项目.完美的解决我的问题,非常nice.
接下来说下另一种方法.这里不再使用relativePath了.当然解决的核心思路,还是利用maven的继承特性.我们既然无法在一个pom文件里解决问题.那我们就多建个pom文件,来平衡上面说的矛盾点.
首先我们父项目里面还是采用dependencyManagement来管理所有的dependency.这就满足了我们第一点的要求.
然后,我们新加个子项目child-pom,这个子项目顾名思义就只会有个pom文件.

<parent>
    <groupId>com.xiaoyu</groupId>
    <artifactId>parent-example</artifactId>
    <version>0.0.1</version>
</parent>
 <groupId>com.xiaoyu</groupId>
  <artifactId>parent</artifactId>
<dependencies>
    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-A</artifactId>
        <version>0.0.1</version>
    </dependency>

    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-B</artifactId>
        <version>0.0.1</version>
    </dependency>
    
    <dependency>
        <groupId>com.xiaoyu</groupId>
        <artifactId>child-C</artifactId>
        <version>0.0.1</version>
    </dependency>
</dependencies>

这个child-pom的唯一的作用就是满足了我们第二点要求.
最后,别的项目引入我们的项目时,就不在是我们上面提到的

<dependency>
    <groupId>com.xiaoyu</groupId>
    <artifactId>parent-example</artifactId>
    <version>0.0.1</version>
</dependency>

而是这个子项目child-pom:

<dependency>
    <groupId>com.xiaoyu</groupId>
    <artifactId>parent</artifactId>
    <version>0.0.1</version>
</dependency>

看到没,核心就是把artifactId从parent-example换成parent,就可以完美解决问题了.
看起来有点违背我固有的认识,以前我一直认为别的项目组引入我的项目,应该就是父项目下的那个pom文件,但其实她们引入的pom应该是我们提供给她们的那个,就是child-pom里的那个.这样只要我们将我们child-pom里面的artifactId写成我们对外的项目名,并对外提供就ok了.我们内部写代码用父项目下的那个pom,对外就用child-pom里面的那个.完美,再次nice.