maven_如何构建一个Maven插件

maven

maven

使用Okta的身份管理平台轻松部署您的应用程序使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。 今天尝试Okta。

由于其插件生态系统的普及,Apache Maven仍然是Java领域最受欢迎的构建工具。 很容易找到现有的插件来完成您的应用程序所需的几乎所有事情,从确保源文件具有许可证标头,到验证版本之间的二进制兼容性。 有时,您需要编写一个自定义插件来满足产品中的要求。

在本教程中,我将向您展示如何构建一个简单的Maven插件来解析项目的当前Git哈希,即git rev-parse --short HEAD

在开始之前,请确保安装Java 8Apache Maven 。 我使用SDKMAN来安装它们。

如果您想观看视频,我创建了此博客文章的截屏视频

创建一个新的Maven项目

我将使用Maven来构建新的Maven插件也就不足为奇了。 您可以使用自己喜欢的IDE来创建一个新项目,但是为了简单起见,我将手动创建一个新的pom.xml文件(在名为example-maven-plugin的新目录中:

<?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/xsd/maven-4.0.0.xsd&>
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.okta.example</groupId>
    <artifactId>example-maven-plugin</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>maven-plugin</packaging>

    <name>Example Maven Plugin</name>
    <description>An Example Maven Plugin</description>

    <properties>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    </properties>

这是因为简单,因为它得到,我已经定义了的Maven GAV(G roup ID,A rtifact ID,V版为),名称,以及最重要的是我所设定的packagingmaven-plugin 。 尽管组ID几乎可以是任何东西,但强烈建议使用反向域名表示法,类似于Java包

添加Maven依赖项

接下来,我需要定义一些对maven-coremaven-plugin-apimaven-plugin-annotations依赖。 这些都按照provided范围限定,这意味着当插件运行时,使用的实际版本将取决于您安装的Apache Maven的版本。

<dependencies>
        <dependency>
            <!-- plugin interfaces and base classes -->
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>3.6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <!-- needed when injecting the Maven Project into a plugin  -->
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-core</artifactId>
            <version>3.6.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <!-- annotations used to describe the plugin meta-data -->
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>3.5</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>

插件构建插件

插件是什么实际上给Maven的它的力量,其核心Maven是只是一个插件框架,所以很自然,我将使用Maven插件来构建一个Maven插件与Maven插件插件。 乌龟一直向下!

maven-plugin-plugin实际上是自动定义的,因为我使用了上面的maven-plugin的包装类型,要使用较新的版本,我可以在pluginManagment部分中更新插件:

<pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-plugin-plugin</artifactId>
                    <version>3.6.0</version>
                </plugin>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-site-plugin</artifactId>
                    <version>3.8.2</version>
                </plugin>
            </plugins>
        </pluginManagement>
</project>

我还包括了Maven站点插件,它是可选的,在后面的文章中有更多介绍。

这就对了! 如果要一次复制并粘贴整个文件,可以从GitHub上获取它。

编写Maven插件代码

在有趣的部分,编写代码! 一个Maven插件实际上是一个或多个“目标”的集合。 每个目标是由一个Java类中定义被称为“魔”(M Aven的平原öLD的J avaöbject)。

创建一个新类: src/main/java/com/okta/example/maven/GitVersionMojo.java

package com.okta.example.maven;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.project.MavenProject;

/**
 * An example Maven Mojo that resolves the current project's git revision and adds 
 * that a new {@code exampleVersion} property to the current Maven project.
 */
@Mojo(name = "version", defaultPhase = LifecyclePhase.INITIALIZE)
public class GitVersionMojo extends AbstractMojo {

    public void execute() throws MojoExecutionException, MojoFailureException {
        // The logic of our plugin will go here
    }
}

没什么大不了的,现在我有了一个新的Maven插件,它有一个名为version目标。 该项目将在初始化项目时执行。 有几个生命周期可供选择,在此示例中,我正在使用“初始化”,因为我希望我的插件在其他插件之前运行。 如果要创建一个插件来创建新文件,则可能要使用“生成资源”阶段。 请查看生命周期参考文档,以获取其他阶段的描述。

此时,我可以使用mvn install构建项目,然后使用以下命令执行插件:

# mvn ${groupId}:${artifactId}:${goal}
mvn com.okta.example:example-maven-plugin:version

但是,由于execute方法为空,因此实际上还不会做任何事情。

添加Maven参数

为了使该插件实际起作用,我将添加几个参数。 Maven参数在MOJO类中定义为字段:

/**
 * The git command used to retrieve the current commit hash.
 */
@Parameter(property = "git.command", defaultValue = "git rev-parse --short HEAD")
private String command;

@Parameter(property = "project", readonly = true)
private MavenProject project;

值得注意的是,Javadoc对于Maven插件很重要,因为在生成特定于插件的文档时将使用它。 由于我们都是优秀的开发人员,因此我们永远不会忘记添加文档,对吗?

Parameter注释告诉Maven向该字段中注入一个值。 这类似于Spring的Value注释。 对于command字段,我将property值设置为git.command 。 这允许用户使用标准-D表示法在命令行上更改值:

mvn com.okta.example:example-maven-plugin:version \
    -Dgit.command="git rev-parse --short=4 HEAD"

注入MavenProject以便直接读取或修改项目中的某些内容也是很常见的。 例如, MavenProject使您可以访问依赖项以及pom.xml定义的任何内容。 就我而言,我将添加一个附加属性,该属性可在以后的构建中使用。

用Java执行命令

现在我们有了command参数,我们需要执行它! 定义一个新的getVersion方法来处理此逻辑:

public String getVersion(String command) throws MojoExecutionException {
    try {
        StringBuilder builder = new StringBuilder();

        Process process = Runtime.getRuntime().exec(command);
        Executors.newSingleThreadExecutor().submit(() ->
            new BufferedReader(new InputStreamReader(process.getInputStream()))
                .lines().forEach(builder::append)
        );
        int exitCode = process.waitFor();

        if (exitCode != 0) {
            throw new MojoExecutionException("Execution of command '" + command 
                + "' failed with exit code: " + exitCode);
        }

        // return the output
        return builder.toString();

    } catch (IOException | InterruptedException e) {
        throw new MojoExecutionException("Execution of command '" + command 
            + "' failed", e);
    }
}

这使用Java的内置Runtime.exec()并捕获输出文本。 任何异常都将作为MojoExecutionException (这将导致生成失败。)

接下来更新execute()方法:

public void execute() throws MojoExecutionException, MojoFailureException {

    // call the getVersion method
    String version = getVersion(command);

    // define a new property in the Maven Project
    project.getProperties().put("exampleVersion", version);

    // Maven Plugins have built in logging too
    getLog().info("Git hash: " + version);
}

就是这样,现在我们只需要使用插件!

Maven插件的用法

到目前为止,我一直在使用以下命令直接执行插件:

mvn com.okta.example:example-maven-plugin:version

通常,插件会添加到pom.xml因此它们会作为构建的一部分自动运行。 为了说明这一点,我将使用以下pom.xml (在另一个目录中)创建一个新的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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.okta.example</groupId>
    <artifactId>example-usage</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>pom</packaging>

    <build>
        <plugins>
            <plugin>
                <groupId>com.okta.example</groupId>
                <artifactId>example-maven-plugin</artifactId>
                <version>1.0-SNAPSHOT</version>
                <configuration>
                    <!-- optional, the command parameter can be changed here too -->
                    <command>git rev-parse --short=4 HEAD</command>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>version</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>

            <plugin>
                <groupId>com.github.ekryd.echo-maven-plugin</groupId>
                <artifactId>echo-maven-plugin</artifactId>
                <version>1.2.0</version>
                <inherited>false</inherited>
                <executions>
                    <execution>
                        <id>end</id>
                        <goals>
                            <goal>echo</goal>
                        </goals>
                        <phase>process-resources</phase>
                        <configuration>
                            <message>${line.separator}${line.separator}
                                The project version is ${project.version}-${exampleVersion}
                                ${line.separator}
                            </message>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

在该项目结果上运行mvn package将给出输出:

[INFO] Git hash: 1ab3行显示了我的插件执行时,该插件定义的新exampleVersion属性由echo-maven-plugin

注意:将插件添加到pom.xml ,可以使用简写形式执行该插件: mvn <prefix>:<goal> ,通常,“ prefix”是工件ID减去“ -maven-plugin” 。 例如mvn example:version

Maven插件中的依赖注入

我们的插件很棒,而且很不错,但是所有代码都挤在一个文件中。 我喜欢将代码分解为易于测试的块。 输入Sisu ,将建立Maven容器。 Sisu是一个基于Guice的IoC容器,它是Spring的替代品。

这一切的真正含义是,我可以使用标准的JSR-330( @Inject )注释来破坏我的代码,而不必担心IoC容器的细节!

src/main/java/com/okta/example/maven/VersionProvider.java创建一个新接口:

package com.okta.example.maven;

import org.apache.maven.plugin.MojoExecutionException;

public interface VersionProvider {
    String getVersion(String command) throws MojoExecutionException;
}

并将Runtime.exec逻辑从GitVersionMojo到新类src/main/java/com/okta/example/maven/RuntimeExecVersionProvider.java

package com.okta.example.maven;

import org.apache.maven.plugin.MojoExecutionException;

import javax.inject.Named;
import javax.inject.Singleton;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.concurrent.Executors;

@Named
@Singleton
public class RuntimeExecVersionProvider implements VersionProvider {
    @Override
    public String getVersion(String command) throws MojoExecutionException {
        try {
            StringBuilder builder = new StringBuilder();

            Process process = Runtime.getRuntime().exec(command);
            Executors.newSingleThreadExecutor().submit(() ->
                new BufferedReader(new InputStreamReader(process.getInputStream())).lines().forEach(builder::append)
            );
            int exitCode = process.waitFor();

            if (exitCode != 0) {
                throw new MojoExecutionException("Execution of command '" + command + "' failed with exit code: " + exitCode);
            }

            // return the output
            return builder.toString();

        } catch (IOException | InterruptedException e) {
            throw new MojoExecutionException("Execution of command '" + command + "' failed", e);
        }
    }
}

我添加了标准Java @Named@Singleton批注,以将该类标记为由IoC容器管理的单例。 这等效于使用Spring的@Component

现在只需更新GitVersionMojo即可注入VersionProvider

@Inject
private VersionProvider versionProvider;

public void execute() throws MojoExecutionException, MojoFailureException {
    String version = versionProvider.getVersion(command);
    project.getProperties().put("exampleVersion", version);
    getLog().info("Git hash: " + version);
}

这就对了! 您可以像以前一样构建和运行插件,并获得相同的结果。

一件事,文档!

关于Maven,我最喜欢的事情之一是插件具有一致的文档结构。 要生成文档,请在pom.xml添加一个新的reporting部分:

<reporting>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-plugin-plugin</artifactId>
            <reportSets>
                <reportSet>
                    <reports>
                        <report>report</report>
                    </reports>
                </reportSet>
            </reportSets>
        </plugin>
    </plugins>
</reporting>

您还应该向项目添加更多元数据,但这是可选的。 例如,我将添加组织和前提条件,因为这些条件和前提条件已包含在生成的站点中:

<organization>
    <name>Example, Inc</name>
    <url>https://google.com/search?q=example.com</url>
</organization>
<prerequisites>
    <maven>3.5.0</maven>
</prerequisites>

现在只需运行mvn site即可生成文档! 在浏览器中打开target/site/plugin-info.html 。 明白为什么所有这些Javadoc都那么重要吗?

1- Maven插件

了解更多

与往常一样,您可以在GitHub找到本教程的完整源代码。 要了解有关构建插件的更多信息, Apache Maven项目提供了出色的文档。 还可以查看以下其他教程:

如果您喜欢本教程,请在Twitter @oktadev上关注我们。 我们还将每周在YouTube频道上发布视频教程。

使用Okta的身份管理平台轻松部署您的应用程序使用Okta的API在几分钟之内即可对任何应用程序中的用户进行身份验证,管理和保护。 今天尝试Okta。

翻译自: https://www.javacodegeeks.com/2019/11/how-to-build-maven-plugin.html

maven

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值