自定义maven插件

young 758 2022-01-20

创建Maven插件工程

通过IDEA创建工程,选择maven-archetype-mojo模板,artifactId命名时采用-maven-plugin结尾

此时pom文件中仅有maven-plugin-api依赖,再添加maven-plugin-annotations依赖,是代码支持maven注解

<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>
  <groupId>young-test</groupId>
  <artifactId>young-maven-plugin</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>maven-plugin</packaging>
  <name>young-test-maven-plugin</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>org.apache.maven</groupId>
      <artifactId>maven-plugin-api</artifactId>
      <version>2.0</version>
    </dependency>
      <dependency>
          <groupId>org.apache.maven.plugin-tools</groupId>
          <artifactId>maven-plugin-annotations</artifactId>
          <version>3.1</version>
      </dependency>
  </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-resources-plugin</artifactId>
                <version>2.4.3</version>
            </plugin>
        </plugins>
    </build>
</project>

之后,创建一个对象,继承AbstractMojo类,重写execute()方法,这个方法就是maven插件的执行方法,同时在类上增加@Mojo注解

@Mojo(name = "test",defaultPhase = LifecyclePhase.CLEAN)
public class MyPlugin extends AbstractMojo {

    @Parameter(property = "path")
    private String path;

    public void execute()  {
        System.out.println("self plugin begin");

        System.out.println(path);

        System.out.println("self plugin end");
    }
}

Mojo注解

/**
 * 此注释会将类标记为 Mojo(即 Maven 插件中的目标)
 * This annotation will mark your class as a Mojo (ie. goal in a Maven plugin).
 *
 * @author Olivier Lamy
 * @since 3.0
 */
@Documented
@Retention( RetentionPolicy.CLASS )
@Target( ElementType.TYPE )
@Inherited
public @interface Mojo
{
    /**
     * goal name (required).唯一必须声明的标注,当用户命令行调用或在pom中配置插件是,需使用该目标名称
     *  如执行命令 my:test 中的test或者下面xml中的goal
     <executions>
	    <execution>
     	   <goals>
        	    <goal>test</goal>
	        </goals>
    	</execution>
	 </executions>
     * @return the goal name
     */
    String name();

    /**默认将该目标绑定至default声明周期的某个阶段,这样在配置使用插件目标时,就无需声明phase,如maven-surefire-plugin的test目标带有@phase tes标注
     * default phase to bind your mojo.
     * @return the default phase
     */
    LifecyclePhase defaultPhase() default LifecyclePhase.NONE;

    /**在运行mojo之前必须解析所有指定范围的依赖,如maven-surefire-plugin的test目标带有requiresDependencyResolution test标注,表示执行测试前,所有测试范围的依赖必须得到解析
     * the required dependency resolution scope.
     * @return the required dependency resolution scope
     */
    ResolutionScope requiresDependencyResolution() default ResolutionScope.NONE;

    /**
     * the required dependency collection scope.
     * @return the required dependency collection scope 
     */
    ResolutionScope requiresDependencyCollection() default ResolutionScope.NONE;

    /**
     * your Mojo instantiation strategy. (Only <code>per-lookup</code> and <code>singleton</code> are supported)
     * @return the instantiation strategy
     */
    InstantiationStrategy instantiationStrategy() default InstantiationStrategy.PER_LOOKUP;

    /**
     * execution strategy: <code>once-per-session</code> or <code>always</code>.
     * @return <code>once-per-session</code> or <code>always</code>
     */
    String executionStrategy() default "once-per-session";

    /**该目标是否必须在一个maven项目中运行(如测试插件用于测试其他项目),默认为true。大部分插件目标需依赖一个项目才能运行,但是,maven-help-plugin的system目标例外,它用来显示系统属性和环境变量信息,无需实际项目。
     * does your mojo requires a project to be executed?
     * @return requires a project
     */
    boolean requiresProject() default true;

    /**是否要求项目报告已经生成,默认为false
     * does your mojo requires a reporting context to be executed?
     * @return requires a reporting context
     */
    boolean requiresReports() default false;

    /**当mojo在多模块项目上运行时,该标注表示目标只会在顶层模块运行。
     * if the Mojo uses the Maven project and its child modules.
     * @return uses the Maven project and its child modules
     */
    boolean aggregator() default false;

    /**为true时,该目标就只能通过命令行直接调用。默认为false
     * can this Mojo be invoked directly only?
     * @return invoked directly only
     */
    boolean requiresDirectInvocation() default false;

    /**是否要求maven必须是在线状态,默认值为false
     * does this Mojo need to be online to be executed?
     * @return need to be online
     */
    boolean requiresOnline() default false;

    boolean inheritByDefault() default true;

    /**
     * own configurator class.
     * @return own configurator class
     */
    String configurator() default "";

    /**
     * is your mojo thread safe (since Maven 3.x)?
     * @return is thread safe
     */
    boolean threadSafe() default false;
}

Parameter注解

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Used to configure your Mojo parameters to be injected by
 * <a href="/ref/current/maven-core/apidocs/org/apache/maven/plugin/MavenPluginManager.html">
 * <code>MavenPluginManager.getConfiguredMojo(...)</code></a>.
 *
 * @author Olivier Lamy
 * @since 3.0
 */
@Documented
@Retention( RetentionPolicy.CLASS )
@Target( { ElementType.FIELD } )
@Inherited
public @interface Parameter
{
    /**
     * alias supported to get parameter value.
     * @return the alias
     */
    String alias() default "";

    /**
     * 配置了property参数,才能从命令行的-D中获取对应的变量值
     * Property to use to retrieve a value. Can come from <code>-D</code> execution, setting properties or pom properties.
     * @return property name
     */
    String property() default "";

    /**     
     * parameter default value, eventually containing <code>${...}</code> expressions which will be interpreted at
     * inject time: see
     * <a href="/ref/current/maven-core/apidocs/org/apache/maven/plugin/PluginParameterExpressionEvaluator.html">
     * PluginParameterExpressionEvaluator</a>. 
     * @return the default value
     */
    String defaultValue() default "";

    /**
     * 参数是否必填,如果为true,没有配置时会报错
     * is the parameter required?
     * @return <code>true</code> if the Mojo should fail when the parameter cannot be injected
     */
    boolean required() default false;

    /**
     * 是否只读属性,是的话则该属性不允许被配置
     * Specifies that this parameter cannot be configured directly by the user (as in the case of POM-specified
     * configuration). This is useful when you want to force the user to use common POM elements rather than plugin
     * configurations, as in the case where you want to use the artifact's final name as a parameter. In this case, you
     * want the user to modify <code>&lt;build&gt;&lt;finalName/&gt;&lt;/build&gt;</code> rather than specifying a value
     * for finalName directly in the plugin configuration section. It is also useful to ensure that - for example - a
     * List-typed parameter which expects items of type Artifact doesn't get a List full of Strings.
     * 
     * @return <code>true</code> if the user should not be allowed to configure the parameter directly
     */
    boolean readonly() default false;
}

打包编译

代码编写完之后,执行mvn install 或者mvn depoly即可

执行插件

pom文件

<build>
	<plugins> 		
 		<plugin>
            <groupId>young-test</groupId>
            <artifactId>young-maven-plugin</artifactId>
            <version>1.0-SNAPSHOT</version>
            <executions>
                <execution>
                    <goals>
                        <!-- 执行目标 -->
                        <goal>test</goal>
                    </goals>
                     <!-- 执行这个目标所在的生命周期,配置了注解的defaultPhase则可以不写 -->
                     <phase>clean</phase>
                </execution>
            </executions>
            <configuration>
                <path>2134</path>
            </configuration>
        </plugin>
    </plugins>
</build>

此时我们执行mvn clean 命令可以看到如下日志,表示我们的自定义插件已经执行了,并且打印出了配置的值2134

[INFO] 
[INFO] --- maven-clean-plugin:3.1.0:clean (default-clean) @ credit-bdp-stream-server ---
[INFO] 
[INFO] --- flatten-maven-plugin:1.2.5:clean (flatten.clean) @ credit-bdp-stream-server ---
[INFO] 
[INFO] --- young-maven-plugin:1.0-SNAPSHOT:test (default) @ credit-bdp-stream-server ---
self plugin begin
2134
self plugin end
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  1.783 s

注意

在pom文件中声明了参数的情况下,使用-D参数是无法覆盖的

例如,执行 mvn clean -Dpath=5678,从日志上可以看出,打印的值还是2134,如果将<path>2134</path>中的值去掉,再执行 mvn clean -Dpath=5678,此时日志中的值就被改为了命令行中的值,也就是说,只有参数没有在xml中初始化的时候,命令-D参数才有效。

使用命令行

如果使用命令行直接调用查询,那么在pom文件中不能申明插件,否则会执行两次该插件

直接调用插件的格式为 groupId:artifactId:version:goal,即young-test:young-maven-plugin:1.0-SNAPSHOT:test,参数使用-D传输

这种写法十分繁琐,如果我们像执行官方插件那样执行我们的插件mvn young:test -Dpath=9527,控制台会提示错误

No plugin found for prefix 'young' in the current project and in the plugin groups [org.apache.maven.plugins, org.codehaus.mojo] available from the repositories [local (H:\JDP\Maven\repository), nexus-releases (http://localhost:8081/nexus/content/groups/public)] -> [Help 1]

这说明,maven模式回去找groupIdorg.apache.maven.pluginsorg.codehaus.mojo的插件,此时需要在settings.xml文件中找到pluginGroups标签,同时添加一个pluginGroup,值为我们自己的groupId即可,添加完之后保存settings.xml,此时再执行mvn young:test -Dpath=9527,即可在控制台看到我们插件已经被执行了。

注意

插件命名未使用-maven-plugin结尾时,无法使用短命令执行

maven内置属性

1、maven属性

内置属性(maven预定义,用户可以直接使用的)

主要有两个常用内置属性——

${basedir}表示项目根目录,即包含pom.xml文件的目录;

${version}表示项目版本。

project.basedir同project.basedir同{basedir};

2、POM属性(使用pom属性可以引用到pom.xml文件对应的元素的值)

${project.build.sourceDirectory}:项目的主源码目录,默认为src/main/java/.
${project.build.testSourceDirectory}:项目的测试源码目录,默认为/src/test/java/.
${project.build.directory}:项目构建输出目录,默认为target/.
${project.outputDirectory}:项目主代码编译输出目录,默认为target/classes/.
${project.testOutputDirectory}:项目测试代码编译输出目录,默认为target/testclasses/.
${project.groupId}:项目的groupId.
${project.artifactId}:项目的artifactId.
${project.version}:项目的version,于${version}等价 
${project.build.finalName}:项目打包输出文件的名称,默认 为${project.artifactId}${project.version}自定义属性(在pom.xml文件的<properties>标签下定义的maven属性)
<project>
<properties>
    <my.pro>proname</my.pro>
</properties>
</project>

在其他地方就可以使用该自定义的属性了:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${my.pro}</version> 
</dependency>

setting.xml文件属性(与pom属性同理,用户可以用以settings.开头的属性引用setting.xml文件的XML元素值)

${settings.localRepository}表示本地仓库的地址

java系统属性(所有的java系统属性都可以用env,开头的maven属性引用)

使用mvn help:system命令可查看所有环境变量;

${env.JAVA_HOME}表示JAVA_HOME环境变量的值;

参考:

https://www.cnblogs.com/oscar1987121/p/10959083.html

https://blog.csdn.net/weixin_41358004/article/details/107399647

https://www.cnblogs.com/cxyyh/p/10847620.html

https://www.cnblogs.com/feiyujun/p/12122159.html