4

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

如果您对细节感兴趣,我将描述我的设置。不过,在此之前,我只想说,我们已经作为一个团队广泛讨论了我们的项目结构,它非常适合我们的需求。我们目前不是在寻找其他结构的建议,而是专门探索 maven 是否可以满足我们的需求。

所以,我们的设置;我会把它归结为要点。我们有两个源项目,A 和 B。它们中的每一个实际上都是另一个的子模块,分别是 ParentA 和 ParentB。ParentA 和 ParentB 在技术上具有许多子模块,但在此示例中,为了简单起见,我将仅显式引用一个。到目前为止,一切都很好。ParentA 引用 A 作为子模块,A 引用 ParentA 作为其父模块。同样的关系适用于 B 和 ParentB 之间。

现在是乐趣。我们希望 ParentA 和 ParentB 都有一个超级父 pom 来继承共享属性和配置,例如依赖管理和插件等。但是我们不希望这个超级父 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 文件中指定可注入的属性,这就像它们最初在模块中指定的一样。当然,所有这些都没有实际修改受源代码控制的 pom。

我们想要评估的是是否有任何范围可以通过插件或补丁修改 maven 来做到这一点。

我们以前从未编写过插件(坦率地说,关于这方面的教程和在线内容很少,而且对开发人员并不友好 - 除非有人有我错过的好教程 :))但我们愿意尝试一下,如果这似乎是可行的。

所以,基本上,

  • 您之前是否自己处理过类似的要求并使其与现有插件一起使用?
  • 我们缺少一个简单的技巧吗?
  • 你有没有写过类似的插件并且可以推荐一个开始的地方?
  • 你知道为什么这样的插件可能不起作用的任何实际原因吗?
  • 您是否在处理 maven 源代码并知道我们是否能够贡献任何生成的代码......以及如果我们愿意,我们应该从哪里开始寻找。

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

非常感谢大家,我知道这是一个有点棘手的问题。

4

1 回答 1

2

对于各种特殊魔法:使用Maven 构建扩展

这是一个不为人知的(对于 maven 来说,sigh)没有很好的文档记录的机制,但据我所知,它确实是一种官方认可的方式来影响整个构建过程。

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,从人工制品管理器加载更多项目并将它们添加到构建反应器,查找一些特定的插件,重塑 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),我们需要从配置管理系统中透明地检索这些服务。向每个开发人员和每个构建服务器推出属性文件是不切实际的,因为环境是异构的。

于 2013-05-08T13:57:29.710 回答