maven插件开发

Maven作为一个优秀的项目管理工具,其插件机制为其功能扩展提供了非常大的便利性。Maven本身提供了很多的插件。如果现有的maven插件无法满足我们的需要,可以自己开发一个。

一、命名规范

Maven的官方插件命名格式为maven-xxx-plugin。为了避免侵犯官方商标,我们一般将自己开发的插件命名为xxx-maven-plugin。遵守这个规范,可以简化插件的运行命令。

二、创建插件项目

Maven的插件是一个Mojo(Maven plain Old Java Object)工程,每一个Mojo就是Maven中的一个执行目标(executable goal),而插件是对单个或多个相关的Mojo做统一分发。一个Mojo就是一个简单的Java类。

以Idea为例,说明下如何创建Mojo工程。

依次点击New -> Project -> Maven,勾选Create from archetype,选择maven-archetype-mojo,填写好相关信息,即可创建一个简单的Mojo工程。

创建好Mojo工程之后,项目工程里会默认生成一个MyMojo类,内容如下:

/**
* Goal which touches a timestamp file.
*
* @goal touch
*
* @phase process-sources
*/

public class MyMojo extends AbstractMojo {
    /**
    * Location of the file.
    * @parameter expression="${project.build.directory}"
    * @required
    */
    private File outputDirectory;
    public void execute() throws MojoExecutionException {
        File f = outputDirectory;
        if ( !f.exists() ) {
            f.mkdirs();
        }
        File touch = new File( f, "touch.txt" );
        FileWriter w = null;
        try {
            w = new FileWriter( touch );
            w.write( "touch.txt" );
        } catch ( IOException e ) {
            throw new MojoExecutionException( "Error creating file " + touch, e );
        } finally {
            if ( w != null ) {
                try {
                    w.close();
                } catch ( IOException e ) {
                    // ignore
                }
            }
        }
    }
}

Mojo类继承自AbstractMojo,每个Mojo类都有一个execute方法,用来实现插件的逻辑。上面自动生成的代码逻辑很简单,找到项目的输出目录(项目根目录下的target文件夹),在该目录下创建一个名为touch.txt的文件,文件内容写入"touch.txt"。

三、使用插件

3.1 Install

在hello-maven-plugin项目中执行maven的install命令

3.2 引入自定义插件

新建或打开另一个maven项目(此处使用的是hello-world项目),在pom文件的 build -> plugins 中加入如下内容:

<build>
    <plugins>
        // ...
        <plugin>
            <groupId>com.justz</groupId>
            <artifactId>hello-maven-plugin</artifactId>
            <version>1.0.0-SNAPSHOT</version>
        </plugin>
    </plugins>
</build>

在该项目的Maven Projects中可以看到hello插件。因为插件项目的artifactId为hello-maven-plugin,名称中的maven和plugin会被忽略,所以插件名称就是一个简单的hello。

在这里插入图片描述
展开插件可以看到Mojo列表,由于项目里只有一个Mojo,且Mojo上用注释@goal指定了名称为touch,所以这里只能看到一个hello:touch。

3.3 执行插件

双击hello:touch就会执行这个插件。执行完毕后,可以看到项目根目录的target文件下多了个touch.txt文件。

3.4 命令行执行插件

命令格式为mvn groupId:artifactId:version:goal,执行如下命令:

mvn com.justz:hello-maven-plugin:1.0.0-SNAPSHOT:touch
由于我们的插件命名符合规范,所以上面的命令可以简写为:
mvn hello:touch

四、Mojo配置方式

Mojo的配置有两种方式,一种是JavaDoc + Tag,即上面的示例代码所使用的方式。另一种是注解,使用@Mojo, @Parameter等annotation来配置。
上例中各个Tag的作用:

  • @goal 指定了这个mojo的名称
  • @phase 插件生效的生命周期
  • @parameter 用于参数,通过expression为参数注入指定的值,比如例子中的${project.build.directory}project.build.directory是maven内置的属性,代表项build的根目录。其他内置属性可参考下面。
  • @required 代表参数是必须的

五、开发Mojo

上面的例子使用的是JavaDoc的方式,接下来使用注解的方式来开发一个自定义的Mojo。

5.1 添加依赖
<dependency>
    <groupId>org.apache.maven.plugin-tools</groupId>
    <artifactId>maven-plugin-annotations</artifactId>
    <version>3.3</version>
</dependency>
5.2 添加Mojo
package com.justz;
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;
@Mojo(name = "greeting", defaultPhase = LifecyclePhase.PROCESS_SOURCES)
public class HelloMojo extends AbstractMojo {

    public void execute() throws MojoExecutionException, MojoFailureException {
        getLog().info("========= Hello ==========");
    }

}

指定Mojo的名称为greeting。逻辑很简单,调用父类的getLog()方法在日志中打印一句话。

5.3 指定 plugin 版本

在hello-maven-plugin项目的pom文件中指定maven-plugin-plugin的版本。plugin版本过低会导致无法识别到带@Mojo注解的类,此处使用的版本为3.2。

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-plugin-plugin</artifactId>
            <version>3.2</version>
        </plugin>
    </plugins>
</build>
5.4 运行

在hello-world项目中,执行mvn hello:greeting,可以在输出日志看到要打印的那句话

➜  hello-world mvn hello:greeting
[INFO] Scanning for projects...
[INFO]                                                                       
[INFO] ------------------------------------------------------------------------
[INFO] Building hello-world 1.0.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO]
[INFO] --- hello-maven-plugin:1.0.0-SNAPSHOT:greeting (default-cli) @ hello-world ---
[INFO] ========= Hello ==========
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.443s
[INFO] Finished at: Wed Nov 14 13:39:47 CST 2018
[INFO] Final Memory: 6M/309M
[INFO] ------------------------------------------------------------------------

六、调试插件

当自定义插件在执行过程中出现了错误时,断点调试一般是最快的解决办法。接下来演示下如何在idea中调试maven插件。

6.1 执行调试命令

在hello-world项目中执行插件调试命令:

mvnDebug hello:greeting
在控制台中可以看到如下输出:

➜  hello-world mvnDebug hello:greeting
Preparing to Execute Maven in Debug Mode
Listening for transport dt_socket at address: 8000

项目正在监听本地的8000端口

6.2 添加远程调试

在hello-maven-plugin项目中,Edit Configurations,在弹出来的对话框中,点击左上角的"+",选择Remote,填写相关内容。因为是本地调试,Host就是localhost。根据上一步的输出结果,将Port改为8000。Name选填,其他不用动,点击OK。

在这里插入图片描述

6.3 执行调试

在execute方法中打好断点,以debug方式启动remote即可。
在这里插入图片描述

七、参数的使用

7.1 使用系统内置属性

通过参数实现一个小功能,打印项目根目录下的文件名

@Mojo(name = "greeting", defaultPhase = LifecyclePhase.PROCESS_SOURCES)
public class HelloMojo extends AbstractMojo {

    @Parameter(defaultValue = "${project.basedir}")
    private File baseDir;

    public void execute() throws MojoExecutionException, MojoFailureException {
        getLog().info("========= Hello ==========");
        File[] files = baseDir.listFiles();
        for (File file : files) {
            getLog().info(file.getName());
        }
    }
}
7.2 使用自定义属性

自定义一个greeting.name属性,输出在hello后面。

@Mojo(name = "greeting", defaultPhase = LifecyclePhase.PROCESS_SOURCES)
public class HelloMojo extends AbstractMojo {

    @Parameter(defaultValue = "${project.basedir}")
    private File baseDir;

    @Parameter(defaultValue = "${greeting.name}")
    private String name;

    public void execute() throws MojoExecutionException, MojoFailureException {
        getLog().info(String.format("========= Hello, %s! ==========", name));
        File[] files = baseDir.listFiles();
        for (File file : files) {
            getLog().info(file.getName());
        }
    }
}

给name属性赋值有两种方式:

  • 使用-D指定,执行如下命令

    mvn hello:greeting -Dgreeting.name=Tom

  • 通过pom文件指定
	<plugin>
    <groupId>com.justz</groupId>
    <artifactId>hello-maven-plugin</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <executions>
        <execution>
            <phase>process-sources</phase>
            <goals>
                <goal>greeting</goal>
            </goals>
            <configuration>
                <name>tom</name>
            </configuration>
        </execution>
    </executions>
</plugin>

八、Maven相关知识点

8.1 生命周期
  • validate: 验证
  • initialize: 初始化构建状态,例如设置属性或创建目录
  • generate-sources: 生成包含在编译中的任何源代码
  • process-sources: 处理源代码
  • generate-resources: 生成包含在包中的资源
  • process-resources: 将资源复制并处理到目标目录中,准备打包
  • compile: 编译项目的源代码
  • process-classes: 处理编译后生成的文件
  • generate-test-sources: 生成包含在编译中的任何测试源代码
  • process-test-sources: 处理测试源代码
  • generate-test-resources: 创建测试资源
  • process-test-resources: 将资源复制并处理到测试目标目录中
  • test-compile: 将测试源代码编译到测试目标目录中
  • process-test-classes: 处理编译后产生的测试文件
  • test: 测试
  • prepare-package: 预打包
  • package: 打包
  • verify: 验证
  • install: 安装
  • deploy: 部署
8.2 属性
8.2.1 内置属性

Maven预定义,用户可以直接使用

  • ${basedir} 表示项目根目录,即包含pom.xml文件的目录;
  • ${version} 表示项目版本;
  • p r o j e c t . b a s e d i r 同 {project.basedir} 同 project.basedir{basedir};
  • ${project.baseUri} 表示项目文件地址;
  • ${maven.build.timestamp} 表示项目构件开始时间;
  • ${maven.build.timestamp.format} 表示属性
  • ${maven.build.timestamp}的展示格式,默认值为yyyyMMdd-HHmm,可自定义其格式,其类型可参考java.text.SimpleDateFormat。用法如下:
<properties>
  <maven.build.timestamp.format>yyyy-MM-dd HH:mm:ss</maven.build.timestamp.format>
</properties>
8.2.2 POM属性

使用pom属性可以引用到pom.xml文件对应元素的值

  • ${project.build.directory} 表示主源码路径;
  • ${project.build.sourceEncoding} 表示主源码的编码格式;
  • ${project.build.sourceDirectory} 表示主源码路径;
  • ${project.build.finalName} 表示输出文件名称;
  • p r o j e c t . v e r s i o n 表 示 项 目 版 本 , 与 {project.version} 表示项目版本,与 project.version,{version}相同;
    参考链接:
    https://maven.apache.org/plugin-developers/index.html
    https://maven.apache.org/plugin-tools/maven-plugin-tools-java/index.html
    https://maven.apache.org/plugin-tools/maven-plugin-tools-annotations/index.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值