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

发布于 2024-10-28 07:25:34 字数 1881 浏览 5 评论 0原文

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

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

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

现在乐趣来了。我们希望 ParentA 和 ParentB 都有一个超级父 pom 来继承共享属性和配置,例如 dependencyManagement 和插件等。但我们不希望这个超级父 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 能够完成这项工作。

理想情况下,每个构建文件首先依赖于从父模块继承的子模块。但是,当我们需要重写此继承时,我们希望能够在构建文件中指定可注入属性,这将与最初在模块中指定它们一样。当然,这一切都没有实际修改受源代码控制的 pom。

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

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

那么,基本上,

  • 您以前自己处理过类似的需求并使其与现有插件一起使用吗?
  • 我们是否缺少一个简单的技巧?
  • 您是否编写过类似的插件并可以推荐一个起点?
  • 您知道这样的插件无法工作的任何实际原因吗?
  • 您是否在处理 Maven 源代码并知道我们是否能够贡献任何生成的代码...以及如果我们愿意的话我们应该从哪里开始寻找。

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

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

A bit of a feasibility question for you regarding Maven. Particular, on whether we can define properties in an aggregating pom and then inject them into the referenced modules, thus allowing that module to locally overwrite the default properties defined in the inheritance hierarchy.

If you're interested in specifics I'll describe my setup. Before I do though, let me just say that we have discussed our project structure as a team extensively and it fits our needs very well. We are not looking for suggestions on other structures at this point, but exclusively exploring whether maven can fulfil our needs.

So, our setup; I'll boil it down to the essentials. We have two source projects, A and B. Each of these is actually a child module of another, ParentA and ParentB respectively. ParentA and ParentB technically have a number of child modules, but in this example I'll only explicitly reference one each for simplicity. So far so good. ParentA references A as a sub-module and A references ParentA as its parent. The same relationship applies between B and ParentB.

Now comes the fun. We would like a super parent pom for both ParentA and ParentB to inherit shared properties and config such as dependencyManagement and plugins etc. But we do NOT want this super parent pom to be responsible for builds. Instead, we would like to define a number of build projects which selectively build the various modules. In this example I'll introduce BuildAB and BuildB. The first builds A and then B, whereas the second builds just B. In reality we have quite a few of these interleaving module groups and dependencies. Finally, just to complete the picture, we have a dependency from B to A.

Let me try and draw this using some ascii art ;)

Inheritance

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

Sub-Module relationships

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

Dependencies

B > A

Now, as it stand it is impossible to use properties from the BuildAB and BuildB files to define dependencies; these Build files are not part of any inheritance tree so nothing will pick up the properties. But we DO want to control the dependency versions differently when running BuildAB and BuildB; simply putting the dependencies in the super-parent is not going to cut it for our requirements.

If you're wondering why this might be consider that one team might be developing the B modules and possibly making minor modifications to A as well. Other developers might be working on the latest and greatest for project A which has repercussions on B thanks to the dependency. We have excellent mechanisms for handling this in sourcecode thanks to Mercurial. But we're really struggling to make this work with Maven.

Ideally, each Build file would in the first instance rely on sub-modules inheriting from the Parent. But when we need to override this inheritance, we would like to be able to specify injectable properties in the Build file, which would act exactly as if they had been specified in the module originally. Of course, all without actually modifying the pom which is being source-controlled.

What we would like to assess is whether there is any scope to modify maven to do this, via a plugin or patch.

We've never written plugins before (and frankly the tutorials and stuff online regarding this are scanty and not really developer-friendly - unless someone has a good tutorial I've missed :)) but we would be willing to give it a try if it seems feasible.

So, basically,

  • have you dealt with similar requirements yourself before and got it working with existing plugins?
  • Is there a simple trick we're missing?
  • Have you written a similar plugin and can recommend a place to start?
  • Do you know of any practical reason why such a plugin may not work?
  • Do you work on the maven source code and know whether we might be able to contribute any resulting code... and where should we start looking if we would like to.

One last comment. We develop in Eclipse, so we also need the build to work without property injection. I expect this would be via the normal inheritance tree.

Many thanks all, I know it's a bit of a tricky question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

分開簡單 2024-11-04 07:25:34

对于各种特殊的魔法:使用ma​​ven 构建扩展

这是一个不太为人所知(对于 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
从构建过程中的特定插件使用),我们需要透明地从配置管理系统中检索。向每个开发人员和每个构建服务器推出属性文件是不切实际的,因为环境是
方式走向异质化。

For all kinds of special magic: use a maven build extension.

This is a not well known (and as usual for maven, sigh) not well documented mechanism, but as far as I can see, it is indeed an officially approved way to influence the build process as a whole.

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);

This function is called right after parsing the pom.xml files and building the basic POM in memory, but before any further build activity starts. In a multi module project, the extension gets called from the root project, even if it is defined in just some submodule. At this point you could in theory do anything with your build process, like just injecting some properties into the pom, loading further projects from the artefact manager and adding them to the build reactor, look up some specific plug-ins, reshape the POM of some module or even build things which aren't declared anywhere (!)

To build such an extension, you place your code into a separate maven project

<?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>

In order to use your extension in some other project, just add the following

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

    <pluginManagement>
    ....

In our specific use case, we had some general services, (esp. database URLs
used from specific plug-ins in the build process) which we need to retrieve from a configuration management system transparently. Rolling out property files to every developer and every build server would not be practical, since the environment is
way to heterogenous.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文