获取Maven聚合器pom以将属性注入模块poms(不使用继承)的可行性

关于Maven的一些可行性问题.特别是,我们是否可以在聚合pom中定义属性然后将它们注入到引用的模块中,从而允许该模块在本地覆盖继承层次结构中定义的默认属性.

如果您对细节感兴趣,我会描述我的设置.在此之前,我要说的是,我们已经广泛讨论了我们的项目结构,并且非常符合我们的需求.我们目前不是在寻找其他结构的建议,而是专门探讨maven是否能满足我们的需求.

那么,我们的设置;我会把它归结为必需品.我们有两个源项目,A和B.这些项目实际上分别是另一个的子模块,ParentA和ParentB. ParentA和ParentB在技术上有许多子模块,但在这个例子中,为了简单起见,我只会明确引用一个子模块.到现在为止还挺好. ParentA引用A作为子模块,A引用ParentA作为其父模块. B和ParentB之间也存在相同的关系.

现在来了很有趣.我们希望ParentA和ParentB的超级父pom继承共享属性和配置,例如dependencyManagement和plugins等.但是我们不希望这个超级父pom负责构建.相反,我们希望定义一些有选择地构建各种模块的构建项目.在这个例子中,我将介绍BuildAB和BuildB.第一个构建A然后构建B,而第二个构建仅B.实际上,我们有相当多的交错模块组和依赖项.最后,为了完成图片,我们有一个从B到A的依赖.

让我尝试使用一些ascii艺术绘制这个;)

遗产

A --> ParentA --> parent
B --> ParentB --> parent

子模块关系

BuildAB ==> { (ParentA ==> A) (ParentB ==> B) }
BuildB ==> (ParentB ==> B)

依赖

B > A

现在,就目前而言,不可能使用BuildAB和BuildB文件中的属性来定义依赖关系;这些构建文件不是任何继承树的一部分,因此没有任何内容可以获取属性.但是我们想要在运行BuildAB和BuildB时以不同方式控制依赖版本.简单地将依赖项放在超级父级中并不会为了我们的要求而削减它.

如果您想知道为什么可能会考虑一个团队可能正在开发B模块并且可能对A进行微小修改.其他开发人员可能正致力于最新和最好的项目A,由于依赖性,它对B产生了影响.由于Mercurial,我们有很好的机制来处理源代码.但我们真的很难与Maven合作.

理想情况下,每个Build文件在第一个实例中都依赖于从Parent继承的子模块.但是当我们需要覆盖这个继承时,我们希望能够在Build文件中指定可注入的属性,它们的行为就像最初在模块中指定的那样.当然,所有这些都没有实际修改受源控制的pom.

我们想要评估的是,是否有任何范围可以通过插件或补丁来修改maven.

我们以前从来没有写过插件(坦率地说,关于这个的教程和内容很少,而且不是真正的开发人员友好 – 除非有人有一个我错过的好教程:))但我们愿意尝试一下这似乎是可行的.

基本上,

>您之前是否已经处理过类似的要求并使用现有的插件?
>我们缺少一个简单的伎俩吗?
>你有没有写过类似的插件,可以推荐一个地方开始?
>您知道为什么这样的插件可能不起作用的任何实际原因?
>您是否正在使用maven源代码并知道我们是否能够提供任何结果代码……我们应该从哪里开始查看是否愿意.

最后一条评论.我们在Eclipse中开发,因此我们还需要构建才能在不注入属性的情况下工作.我希望这将通过正常的继承树.

非常感谢所有人,我知道这是一个棘手的问题.

最佳答案 对于各种特殊魔法:使用maven构建扩展.

这是一个众所周知的(并且像往常一样对于maven,叹气)没有详细记录的机制,但据我所知,它确实是一种正式批准的方式来影响整个构建过程.

import org.apache.maven.AbstractMavenLifecycleParticipant;
import org.apache.maven.execution.MavenSession;
import org.codehaus.plexus.component.annotations.Component;
import org.codehaus.plexus.component.annotations.Requirement;
import org.codehaus.plexus.logging.Logger;

@Component(role = AbstractMavenLifecycleParticipant.class, hint = "mySpecialService")
public class MySpecialExtension
    extends AbstractMavenLifecycleParticipant
{

    @Requirement
    private Logger logger;

    @Override
    public void afterProjectsRead( MavenSession session ) {
        // ...do you magic here

        // for example, to set some POM properties
        Properties sysProps = session.getSystemProperties();
        ....
        Properties projProps = session.getCurrentProject().getProperties();
        projProps.setProperty("..",val);

在解析pom.xml文件并在内存中构建基本POM之后,但在任何进一步的构建活动开始之前,立即调用此函数.在多模块项目中,扩展从根项目调用,即使它仅在某个子模块中定义.在这一点上,理论上你可以对你的构建过程做任何事情,比如只是将一些属性注入到pom中,从artefact管理器加载更多项目并将它们添加到构建反应器,查找一些特定的插件,重塑POM的内容.一些模块甚至构建未在任何地方声明的东西(!)

要构建此类扩展,请将代码放入单独的maven项目中

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <prerequisites>
        <maven>3.0</maven>
    </prerequisites>

    <name>my-special-service</name>
    <groupId>my.group</groupId>
    <artifactId>my-special-service</artifactId>
    <packaging>jar</packaging>

    <parent>
       ....
    </parent>

    <properties>
        <mavenApiVer>3.0.5</mavenApiVer>
        <mavenModelVer>2.2.1</mavenModelVer>
    </properties>

<build>
    <plugins>
        <!-- Maven Build Extension -->
        <plugin>
            <groupId>org.codehaus.plexus</groupId>
            <artifactId>plexus-component-metadata</artifactId>
            <version>1.5.5</version>
            <executions>
                <execution>
                    <goals>
                        <goal>generate-metadata</goal>
                        <!-- goal>generate-test-metadata</goal -->
                    </goals>
                </execution>
            </executions>
            </plugin>
            <!-- Maven Build Extension -->
        </plugins>
    </build>


    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-project</artifactId>
            <version>${mavenModelVer}</version>
        </dependency>

        <!-- Maven Build Extension -->
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-compat</artifactId>
            <version>${mavenApiVer}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-core</artifactId>
            <version>${mavenApiVer}</version>
        </dependency>
        <!-- Maven Build Extension -->

        ....

    </dependencies>
</project>

要在其他项目中使用您的扩展,只需添加以下内容即可

<build>
    <extensions>
        <extension><!-- Maven Build Extension: my Special Service -->
            <groupId>my.group</groupId>
            <artifactId>my-special-service</artifactId>
            <version>.....</version>
        </extension>
    </extensions>

    <pluginManagement>
    ....

在我们的特定用例中,我们有一些常规服务(特别是数据库URL)
我们需要从配置管理系统中透明地检索构建过程中的特定插件.将属性文件分发给每个开发人员和每个构建服务器都不实用,因为环境是
异化的方式.

点赞