获取Maven聚合器pom以将属性注入模块poms(不使用继承)的可行性 [英] Feasibility of getting Maven aggregator pom to inject properties into module poms (not using inheritance)

查看:155
本文介绍了获取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  - >父母
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 build extension



这是一个众所周知的(并且像往常一样对于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
{

@要求
私人记录器记录器;

@Override
public void afterProjectsRead(MavenSession session){
// ...你这里有魔力

//例如,要设置一些POM属性
属性sysProps = session.getSystemProperties();
....
属性projProps = session.getCurrentProject()。getProperties();
projProps.setProperty(..,val);

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



要构建这样的扩展,您可以将代码放入单独的maven项目中

 <?xml version =1.0encoding =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>
<先决条件>
< 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:我的特殊服务 - >
< groupId> my.group< / groupId>
< artifactId> my-special-service< / artifactId>
< version> .....< / version>
< / extension>
< / extensions>

< pluginManagement>
....






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


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.

解决方案

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.

这篇关于获取Maven聚合器pom以将属性注入模块poms(不使用继承)的可行性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆