Maven2 - 插件管理和父子关系问题

18

从maven 文档 中获取的信息:

pluginManagement:与插件一起使用的元素。Plugin Management 包含插件元素,配置方式类似,但不同之处在于,它旨在为继承自此项目的项目构建配置,并非为此特定项目构建配置插件信息。然而,这仅配置实际在子项目中 plugins 元素中引用的插件。子项目有权覆盖 pluginManagement 定义。

现在问题是:如果我在我的父 POM 中有这个内容

  <build>
   <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.0</version>
          <executions>
             Some stuff for the children
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>

当我在父项目上运行mvn help:effective-pom时,我得到了我想要的结果,即build下直接的插件部分(执行工作的部分)为空。

现在,如果我执行以下操作:

  <build>
   <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.0</version>
          <executions>
             Some stuff for the children
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.0.2</version>
    <inherited>true</inherited>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>
</plugins>
  </build>

使用mvn help:effective-pom命令后,我得到了我想要的内容,插件中只包含已声明的内容,而pluginManagement部分被忽略。

但是当进行以下更改时

  <build>
   <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.0</version>
          <executions>
             Some stuff for the children
            </execution>
          </executions>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <artifactId>maven-dependency-plugin</artifactId>
          <version>2.0</version>
          <inherited>false</inherited> <!-- this perticular config is NOT for kids... for parent only -->
            <executions>
             some stuff for adults only
            </execution>
          </executions>
       </plugin>
    </plugins>
  </build>

运行 mvn help:effective-pom,插件管理部分的内容将会添加在已经声明的内容之上。因此:

  <build>
   <pluginManagement>
     ...
   </pluginManagement>
    <plugins>
      <plugin>
        <artifactId>maven-dependency-plugin</artifactId>
          <version>2.0</version>
          <inherited>false</inherited> <!-- this perticular config is NOT for kids... for parent only -->
              <executions>
                 Some stuff for the children
                </execution>
            <executions>
             some stuff for adults only
            </execution>
          </executions>
       </plugin>
    </plugins>
  </build>
有没有一种方法可以从父POM的“section”中排除子级部分?实际上,我想要的是pluginManagement的行为与文档所述完全一致,也就是说,我只希望它适用于子级,而不适用于声明它的项目。
此外,是否有一种方法可以通过在项目的普通构建部分声明插件来覆盖pluginManagement中的部分?无论我尝试什么,都会得到添加了该部分以执行操作,但我无法覆盖已经存在的部分。
编辑:
我从未找到过可接受的解决方案,因此问题仍然存在。最接近的解决方案是下面提供的解决方案,目前是该问题的已接受解决方案,直到出现更好的解决方案。现在有三种方法可以实现所需的结果(根据当前POM在继承层次结构中的位置调节插件行为):
1-使用配置文件,这将起作用,但您必须注意配置文件不会被继承,这有点违反直觉。如果激活,它们将应用于声明配置文件的POM,然后将此生成的POM传播下去。因此,激活配置文件的唯一方法是在命令行上明确指定它(至少我没有找到其他方法)。属性、文件和其他激活方式无法激活POM,因为触发器不在声明配置文件的POM中。
2 - (这是我最终采取的做法)在父级中声明插件为非继承性,并在每个想要的子级中重新声明(复制-粘贴)该块内容。虽然不理想,但它很简单并且起作用。
3-拆分父POM的汇总特性和父特性。然后,由于仅适用于父级的部分位于不同的项目中,现在可以像最初打算的那样使用pluginManagement。然而,这意味着必须创建一个新的人工项目,它不会对最终产品产生贡献,只服务于云系统。这是一个明显的概念渗漏情况。此外,这只适用于我的特定情况,难以推广,因此我放弃了尝试使其工作的努力,转而使用不太美观但更加清晰的剪切和粘贴补丁(如2所述)。
如果看到这个问题的任何人都有更好的解决方案,无论是因为我对Maven的认识不足还是因为工具已经发展到允许这样做,请在此发布解决方案以供将来参考。
感谢大家的帮助 :-)
4个回答

14

将插件配置添加到pluginManagement中意味着如果声明了该插件,则将使用此配置,但仍需要在任何想要使用它的POM的构建部分中声明该插件。

从您引用的部分中解释此内容的关键部分是:

  

然而,这只配置了实际上在子代中的plugins元素中被引用的插件

因此,如果您在子POM中执行此操作,则将应用来自父级的配置:

<build>
  <plugins>
    <plugin>
      <artifactId>maven-dependency-plugin</artifactId>
    </plugin>
  </plugins>
</build>

更新:为了回答实际问题,来自pluginManagement部分的内容始终与任何插件声明合并。为了避免父POM这样做,您可以在配置文件中定义pluginManagement部分,并在子项目上激活该配置文件,但不激活父POM。然后,子项目将必须声明该配置文件。

例如:

<profiles>
  <profile>
    <id>for-children</id>
    <build>
      <pluginManagement>
        <plugins>
          <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <version>2.0</version>
            <executions>
              <!--Some stuff for the children-->
            </executions>
          </plugin>
        </plugins>
      </pluginManagement>
    </build>  
  </profile>
</profiles>
<build>
  <plugins>
    <plugin>
      <artifactId>maven-dependency-plugin</artifactId>
        <version>2.0</version>
        <inherited>false</inherited> <!-- this perticular config is NOT for kids... for parent only -->
          <!--some stuff for adults only-->
        </executions>
     </plugin>
  </plugins>
</build>

为了使其工作,我必须在命令行上显式激活配置文件。这意味着为了大大简化一个很少编辑的文件(pom.xml),我必须使一个经常使用的命令变得相对复杂。我已经尝试并转换了各种问题。我认为唯一的解决方案是将聚合与父POM分开,但我犹豫不决,因为它创建了一个除了构建系统结构之外没有任何实际用途的人工项目。 - Newtopian
2
我不会担心分离父级和聚合器,你拥有的项目越多,它们作为整体就越不相似,因此你更可能定义具有不同父级的项目集,这与你希望构建它们的分组正交。没有完美的答案。我认为这与面向对象编程中的继承与组合问题相同。 - Rich Seller
我发现,当你有一个父POM包含一个也是父级的模块时,超级父级中的插件管理器(pluginManagent)中的插件也会在子级父级中执行,即使它们没有被显式声明。 - Dormouse

6
我曾经认为,子POM可以从其父级的pluginManagement部分继承插件定义,并通过引用它们的ID并将执行绑定到阶段来指定仅要运行的执行。只要父级定义在pluginManagement中(而不是直接在插件中)且未绑定到阶段,该阶段只会运行特定的执行(带有ID)。
从上面的描述和我的问题来看,似乎这不是真的:子POM将继承插件的整个配置,包括所有执行。就执行而言,子级唯一能做的是覆盖特定值-它无法选择要运行哪些执行,哪些不运行。
这是一个错误吗?如果所有执行都会运行,那么将每个执行绑定到阶段(或不绑定)有什么用处?我只在maven-dependency-plugin:unpack中看到过这种情况(绑定到package阶段),但对于其他插件,我可能只是幸运而已...
该死。

也许这可以阐明问题:http://maven.apache.org/guides/mini/guide-default-execution-ids.html。看起来在Maven 2.2中可能已经修复了。现在,如果m2eclipse只能真正与外部Maven安装一起工作... - Cornel Masson
嗯...有趣,我得试一下,尽管我现在是爱恨交织中 Maven 的仇恨部分...再次... Maven 90% 的时间都很棒,能够奇迹般地完成任务...但剩下的10%就让人无法忍受...就像最好的和最差的融合在一起,其中一个与另一个无法分辨...好吧,说够了...回到 POM。 - Newtopian
1
@Newtopian,自从我上一篇文章以来,我已经在Maven中记录了一个错误(请参见http://jira.codehaus.org/browse/MNG-4595),因为在我看来,这似乎只是maven-dependency-plugin的问题。 - Cornel Masson
1
我不知道在执行时使用 combine.self="override" 技巧是否能解决你的问题?这样子代就可以忽略父级执行。但是,似乎这个特性只适用于 <configuration> 内部的项目。http://www.sonatype.com/people/2011/01/maven-how-to-merging-plugin-configuration-in-complex-projects/ - Scott Carey

5
在父POM中,您应该配置带有声明为<goals>的执行,但不要声明<phase>。然后在子POM中,您应该声明:
<plugin>
  <artifactId>some-plugin</artifactId>
  <executions>
    <execution>
      <id>execution-id</id>
      <phase>partcular-phase</phase>
    </execution>
  </executions>
</plugin>

插件在子POM中定义阶段之前不会被执行。因此,您需要在每个子POM(或层次结构中间)中显式地将执行绑定到阶段,但是您不需要复制这些执行的配置。

请注意,许多插件具有默认阶段,例如Enforcer插件默认绑定到validate。即使您没有明确将插件绑定到阶段,它也会被绑定并执行插件。要克服这个问题,在父级中使用不存在的阶段:

<execution>
  <id>execution-id</id>
  <goals><goal>some-goal</goal></goals>
  <phase>none</phase>
</execution>

有趣!不幸的是,我换了工作,不再经常使用Maven。虽然我很想念它,但MSBuild可能会让人感到... 嗯... 很烦人,为了保持礼貌。如果有人通过这个页面寻找答案,请尝试这个解决方案,并告诉我们它对你有何作用。 - Newtopian

0

你必须为执行分配一个ID,这样Maven才知道哪些会相互覆盖,哪些是独立的。


1
我已经尝试过了,但是很遗憾,我无法使用这种方法删除执行部分。此外,使用相同ID更改值只会覆盖该单个值,因此为使其正常工作,我必须重新声明整个部分,并使用转移操作的值,这违背了集中化此行为以避免重复的目的。 - Newtopian

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接