65.9K
CodeProject 正在变化。 阅读更多。
Home

Maven 3 插件开发

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2015年7月30日

CPOL

4分钟阅读

viewsIcon

16653

新一代,基于注解的 Maven 3 插件开发。告别 Javadoc!

引言

首先,距离我上次在 CodeProject 上写文章已经过去很长时间了。能在这里写下这些内容,我感到很兴奋 :)

总的来说,Maven 一直支持插件开发。而且一直以来都不是一件复杂的事情。但自从 Java 5 引入了注解,Maven 就在 3.0 版本中决定支持使用注解进行插件开发。 

其中会包含一些表达式,例如 mojo, threadSafe 等。我将在相应的章节中进行解释。

背景

Maven 插件开发的基本思想是开发一个工具,帮助你整理一些混乱的任务。例如,如果你正在进行一些构建后或构建前的工作,插件就是你所需要的。

对我来说,我需要为一个我们的产品开发一个插件。该产品需要四个或更多 Maven 插件来组装最终的 War 文件,创建过程非常复杂。我的任务是创建一个插件,一次性完成 4-5 个插件的工作。 

与此同时,你可以在 这里 了解更多关于 Maven 3 插件开发的信息。

使用代码

Mojo 基本上意味着 Pojos (Plain Old Java Objects)。 而且自从 Maven 3 和 Java 5 以来,我们可以很容易地使用注解编写 mojo。对我来说,它们看起来就像 Spring 组件。但当然,除了 Spring 组件和 mojo 的外观之外,它们之间没有相似之处。

以下是编写 Maven 3 插件的要求:

  • 当然,mojos 应该放在 Maven 项目中。为此创建一个经典的 Maven 项目。为了快速设置,你可以使用以下 archetype,但我建议你遵循我的其他步骤以充分理解所有开发过程。
maven-archetype-plugin
  • 要使用注解,你必须在你的 pom.xml 中添加以下依赖:
<groupId>org.apache.maven.plugin-tools</groupId>
<artifactId>maven-plugin-annotations</artifactId>
<version>3.4</version> <!-- This is my version, please check latest -->
<scope>provided</scope> <!-- It comes from maven itself, that's why we are making it provided -->
  • 我们需要访问一些 Maven 变量,例如 project (包含项目几乎所有信息) 等。这样,我们就可以访问使用我们插件的项目的依赖项、构建路径信息等。
<groupId>org.apache.maven</groupId>
<artifactId>maven-core</artifactId>
<version>3.2.3</version> <!-- This is my version, please check latest -->
  • 我们的插件 Maven 项目的 packaging 应该是:
<packaging>maven-plugin</packaging>
  • (可选) 在我的 Maven 插件中,我需要执行其他插件来继续操作,所以我将以下依赖项添加到我的 pom.xml 中。因此,我能够从我的插件内部执行其他插件。
<groupId>org.twdata.maven</groupId>
<artifactId>mojo-executor</artifactId>
<version>2.2.0</version> <!-- This is my version, please check latest -->
  • 最后,我们必须将 Maven 项目的默认描述符执行覆盖为 process-classes。没有明确的解释为什么我们要覆盖它。但你可以在 这里 了解更多。
<build>
<plugins>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-plugin-plugin</artifactId>
    <version>3.4</version>
    <executions>
        <execution>
        <id>default-descriptor</id>
        <phase>process-classes</phase>
        </execution>
    </executions>
</plugin>
</plugins>
</build>

现在,一切都准备就绪,可以编写一个 mojo。 我们可以通过用 @Mojo 注解来指定一个类作为 Mojo。并且它必须继承自 AbstractMojo 类。通过这种方法,我们将重写一个方法,Maven 将知道在执行插件时该做什么。

一个简单的 mojo 会如下所示。 

@Mojo(name = "my-goal", threadSafe = true, defaultPhase = LifecyclePhase.COMPILE, requiresDependencyResolution = ResolutionScope.TEST)
public class MyMojo extends AbstractMojo{

}

属性描述如下:

  • name - 你的插件的目标,你将在 <execution><goals><goal> 标签中写入它。
  • threadSafe - Maven 3 支持并行构建,将此属性设置为 true,你就可以让 Maven 同步运行此插件。
  • defaultPhase - 这是你插件的默认阶段,插件用户可以覆盖它。
  • requiresDependencyResolution - 这是你的插件的依赖覆盖部分。TEST 意味着你可以访问所有依赖项。有关更多信息,请参见 这里

接下来我们要做的就是重写 AbstractMojoexecute 方法。

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException{
        getLog().info( "Now working my first plugin..." );
    }

通过将以下依赖项添加到你的 mojo 中,你可以访问所有项目属性。

    @Parameter(defaultValue = "${project}", readonly = true)
    private MavenProject project;

这是一个例子

for( Dependency dependency : project.getDependencies() ){
    getLog().info( dependency.getGroupId() );
}

// prints all dependencies group ids.

Parameter 注解允许你定义 Maven 参数。通过 defaultValue 属性,我们访问了一个 Maven 属性,并将其设置为 readonly 以确保没有人可以覆盖它。

最后,我想展示如何在你的插件代码中执行一个 Maven 插件。这是我的需求,但完全是可选的。execute 方法中的一切都取决于你的需求,请记住这一点。

        executeMojo(
                plugin( groupId( "org.apache.maven.plugins" ), artifactId( "maven-resources-plugin" ), version( "2.7" ) ),
                goal( "copy-resources" ),
                configuration(
                        element( name( "outputDirectory" ), project.getBuild().getDirectory() + "/test" ),
                        element( name( "overwrite" ), "true" ),
                        element(
                                name( "resources" ),
                                element(
                                        name( "resource" ),
                                        element( name( "directory" ), project.getBuild().getDirectory() + "/" ),
                                        element( name( "excludes" ), element( name( "exclude" ), "**/com/sercanozdemir/**" ),
                                                element( name( "exclude" ), "**/WEB-INF/**" ) ) ) ) ), executionEnvironment( project, mavenSession, pluginManager ) );

mavenSessionpluginManager 变量来自 Maven 本身。

    @Parameter(defaultValue = "${session}", readonly = true)
    private MavenSession mavenSession;

    @Component
    private BuildPluginManager pluginManager;

@Component 注解用于配置 Plexus 组件或 Maven 上下文组件的注入。

引用

Plexus 是一个平台,由一个控制反转 (Inversion-of-Control) 容器以及许多实用库组成,包括Classworlds 类加载器框架。Maven 是在其之上构建的,但已经进行了大量工作用 Guice 取代它

Plexus 还提供一系列实用库,这些库被核心 Maven 插件大量使用 —— 比如 plexus-utilsplexus-archiver 等等。 ~/.m2/repository/org/codehaus/plexus/ 在任何运行过 Maven 的机器上都会相当繁忙。

最后,这里是一个使用这个简单插件的示例:

<build>
    <plugins>
        <plugin>
            <groupId>com.sercanozdemir.plugin</groupId>
            <artifactId>mymojo</artifactId>
            <version>1.0.0-SNAPSHOT</version>
            <executions>
                <execution>
                    <goals>
                        <goal>my-goal</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>

此外,你可以通过从用户那里获取更多参数或更改插件的默认阶段来扩展你的代码。

关注点

目前互联网上关于 Maven 3 插件开发方面的源码资料较少,希望这能帮助到一些有需要的人。

谢谢!

© . All rights reserved.