• Maven插件开发


    简介

    Maven本身只是一套框架,它的功能基于全部依赖于插件来实现。因此,掌握插件开发深度定制Maven的必修课。

    https://maven.apache.org/plugins/index.html

    插件本身也是Maven构件,构件标识的命名约定是 -maven-plugin。不要命名为 maven--plugin,这种命名模式由官方插件(组标识 org.apache.maven.plugins)保留。

    每个Maven插件包含一或多个Mojo,每个Mojo实现了一个插件目标(goal),Mojo通常编写为Java类。插件就是一系列Mojo的集合。

    插件必须在自己的JAR包的 META-INF/maven/plugin.xml中提供描述符信息,你不需要手工编写描述符,使用Maven插件工具注解即可自动生成。

    入门

    本章我们编写一个最简单的插件,它不需要参数,仅仅简单的打印一段消息。

    第一个Mojo

    可以将mojo理解为插件的一个目标(goal)的实现类。你需要使用@Mojo注解来声明一个类是mojo:

    Java

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    package sample.plugin;

    import org.apache.maven.plugin.AbstractMojo;

    import org.apache.maven.plugin.MojoExecutionException;

    import org.apache.maven.plugins.annotations.Mojo;

    @Mojo( name = "sayhi")

    public class GreetingMojo extends AbstractMojo

    {

        public void execute() throws MojoExecutionException

        {

            getLog().info( "Hello, world." );

        }

    }

    抽象类AbstractMojo包含了实现mojo所需的基础代码,我们仅仅需要实现execute方法就可以了。execute方法可以抛出两种异常:

    1. MojoExecutionException:表示意外错误发生,控制台会显示BUILD ERROR消息
    2. MojoFailureException:表示非意外的错误发生,例如编译是白。控制台会显示BUILD FAILURE消息

    构建插件

    插件本身也是Maven项目,因此你需要编写POM,示例:

    XML

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

      4.0.0

      sample.plugin

      <artifactId>hello-maven-plugin

      1.0-SNAPSHOT

      

      maven-plugin

      Sample Parameter-less Maven Plugin

      

        

          org.apache.maven

          maven-plugin-api

          3.0

        

        

        

          org.apache.maven.plugin-tools

          maven-plugin-annotations

          3.4

          provided

        

      

    使用插件

    另创建一个Maven项目,添加以下配置: 

    XML

    1

    2

    3

    4

    5

    6

    7

    8

    9

      

        

          sample.plugin

          hello-maven-plugin

          1.0-SNAPSHOT

        

      

    然后调用我们的插件:

    Shell

    1

    2

    # mvn groupId:artifactId:version:goal

    mvn sample.plugin:hello-maven-plugin:1.0-SNAPSHOT:sayhi

    简化命令行

    上面调用插件的mvn命令参数非常冗长,缩短的方式有几种:

    1. 如果希望执行本地仓库中,插件的最新版本,则version可以省略
    2. 可以为插件分配快捷前缀,如果插件命名遵循了 ${prefix}-maven-plugin格式则prefix自动为前缀。调用命令可以简化为 mvn sample.plugin:hello:sayhi
    3. 可以将组标识添加到Maven的settings.xml的pluginGroups,这样就可以进一步省略组标识:
      ~/.m2/settings.xml

      XML

      1

      2

      3

          sample.plugin

      调用命令简化为 mvn hello:sayhi

    附到生命周期

    在目标项目中增加如下配置:

    XML

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

      

        

          sample.plugin

          hello-maven-plugin

          1.0-SNAPSHOT

          

            

              <phase>compile

              

                sayhi

              

            

          

        

      

    则在构建生命周期的compile阶段,sayhi目标自动执行。

    Mojo原型

    你可以从原型创建插件项目,避免手写样板代码: 

    Shell

    1

    2

    3

    4

    5

    mvn archetype:generate \

        -DgroupId=sample.plugin \

        -DartifactId=hello-maven-plugin \

        -DarchetypeGroupId=org.apache.maven.archetypes \

        -DarchetypeArtifactId=maven-archetype-plugin

    参数化Mojo

    Mojo可以支持参数,目标项目的POM中可以声明传入的参数值,你也可以在命令行中以-D系统属性的风格传入参数值。

    要定义Mojo参数,只需要为Mojo类的字段添加注解:

    Java

    1

    2

    @Parameter( property = "sayhi.greeting", defaultValue = "Hello World!" )

    private String greeting;

    上面的代码定义了一个参数greeting,并给定了默认值。此参数对应的系统属性为sayhi.greeting。

    参数值可以使用 ${project.version}这样的表达式,来引用目标项目的属性。

    POM配置参数值

    XML

    1

    2

    3

    4

    5

    6

    7

    8

    9

      sample.plugin

      hello-maven-plugin

      1.0-SNAPSHOT

      

        

        Welcome

      

    插件参数表达式

    在插件参数表达式中,你可以使用以下对象:

    对象说明
    session当前 MavenSession对象 
    session.*
    localRepositoryMavenSession.getLocalRepository()
    reactorProjectsMavenSession.getProjects()
    repositorySystemSessionMavenSession.getRepositorySession()
    projectMavenSession.getCurrentProject()
    project.*
    pom.*
    executedProjectMavenProject.getExecutionProject()
    settingsMavenSession.getSettings()
    settings.*
    basedirMavenSession.getExecutionRootDirectory(),为空则取
    System.getProperty( "user.dir" )
    mojoExecution当前MojoExecution对象
    mojo
    mojo.*
    pluginMojoExecution.getMojoDescriptor().getPluginDescriptor() 
    plugin.*
    *还可以直接使用系统属性、项目属性

    类型转换规则

    配置中的文本转换为Mojo参数字段的规则如下:

    参数字段类型文本表示
    布尔型true或者false
    整数包括byte, Byte, int, Integer, long, Long, short, Short,支持负号
    浮点数包括double, Double, float,  Float,支持科学计数法
    java.util.Date

    支持格式:

    yyyy-MM-dd HH:mm:ss.S a  例如2005-10-06 2:22:55.1 PM
    yyyy-MM-dd HH:mm:ssa  例如2005-10-06 2:22:55PM

    java.io.File文件系统路径,例如c:\temp
    java.net.URLURL,例如https://gmem.cc

    复杂参数

    多值参数

    Mojo字段可以使用数组、集合类:

    Java

    1

    2

    @Parameter

    private String[] myArray;

    对应POM配置示例: 

    XML

    1

    2

    3

    4

        value1

        value2

    映射类型的字段POM配置示例,参数名为myMap: 

    XML

    1

    2

    3

    4

        value1

        value2

    Properties类型的POM配置示例,参数名为myProperties:

    XML

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

      

        propertyName1

        propertyValue1

      

      

        propertyName2

        propertyValue2

      

    对象参数 

    Mojo参数字段也可以是任意对象类型: 

    Java

    1

    2

    @Parameter

    private MyObject myObject;

    对应POM配置示例:  

    XML

    1

    2

    3

        test

    测试和调试

    单元测试

    用于测试单个Mojo的功能,并仿冒Maven的其它部分。

    使用PlexusTestCase

    你可以像编写普通Junit测试用例那样,进行Mojo单元测试。但是,大部分情况下Mojo都需要被注入一个Maven项目的引用,可以 extends PlexusTestCase达成变量注入的目的。

    maven-plugin-testing-harness

    此工具专门用于测试 org.apache.maven.reporting.AbstractMavenReport#execute()

    集成测试

    在一个真实的Maven Build中测试Mojo,你需要提供一个测试用的Maven项目,插件需要安装到本地仓库。

    maven-verifier

    Maven验证器为你的JUnit测试用例提供以下功能:

    1. 启动Maven
    2. 根据构建的输出、日志信息进行断言
    3. 从src/test/resources目录抽取出一个Maven项目,并存放到临时工作目录中,针对此项目进行测试
    4. 操控本地仓库

    Maven项目本身也在用此验证器进行集成测试,下面是一些说明如何使用该验证器的代码片段:

    Java

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    public class TrivialMavenVerifierTest extends TestCase {

        public void testMyPlugin() throws Exception {

            // 从/src/test/resources/中抽取测试用的Maven项目

            File testDir = ResourceExtractor.simpleExtractResources( getClass(), "/my-dummy-maven-project" );

            Verifier verifier;

            // 首选需要保证,此test项目产生的构件已经从本地仓库移除

            verifier = new Verifier( testDir.getAbsolutePath() );

            verifier.deleteArtifact( "org.apache.maven.its.itsample", "parent", "1.0", "pom" );

            verifier.deleteArtifact( "org.apache.maven.its.itsample", "checkstyle-test", "1.0", "jar" );

            verifier.deleteArtifact( "org.apache.maven.its.itsample", "checkstyle-assembly", "1.0", "jar" );

            // 执行Maven命令

            List cliOptions = new ArrayList();

            cliOptions.add( "-N" );

            verifier.executeGoal( "install" );

            // 验证上述命令是否成功

            verifier.verifyErrorFreeLog();

            // 清理,准备下一个命令的执行

            verifier.resetStreams();

        }

    }

    maven-invoker-plugin

    这是一个插件,可以调用Maven,并提供一些BeanShell或Groovy的测试脚本: 

    XML

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

      

        

          org.apache.maven.plugins

          maven-invoker-plugin

          1.10

          

            src/it

            

              **/pom.xml

            

            verify

          

          

            

              

                run

              

            

          

        

        ...

      

    调试

    远程调试

    要调试Maven插件,可以使用远程调试的方式。

    你需要用 mvnDebug而非mvn来调用Maven,此命令默认会监听8000端口,等待Debugger的连接。

    示例:

    Shell

    1

    2

    3

    4

    5

    mvnDebug cc.gmem.yun.maven.plugins:maven-archetype-plugin:3.1.1:create-from-project \

        -Darchetype.properties=archetype.properties -Darchetype.postPhase=package -Darchetype.partialArchetype=true

    # Preparing to execute Maven in debug mode

    # Listening for transport dt_socket at address: 8000

    本地调试

    配合Intellij IDEA等开发工具,可以很容易实现本地调试。

    在你的插件项目中,创建一个Maven的运行配置,设置环境变量:

    Shell

    1

    MAVEN_DEBUG_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000"

    然后Maven的Command line调用你的插件的Mojo,配置好了点击调试按钮即可。 

    Maven插件工具注解

    所有注解示例

    Java

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    37

    38

    39

    40

    41

    42

    43

    44

    45

    46

    47

    48

    49

    50

    51

    52

    53

    54

    55

    56

    57

    58

    59

    60

    61

    62

    63

    64

    65

    66

    67

    68

    69

    70

    71

    72

    73

    74

    75

    76

    77

    78

    79

    80

    81

    82

    83

    import org.apache.maven.execution.MavenSession;

    import org.apache.maven.plugin.AbstractMojo;

    import org.apache.maven.plugin.MojoExecution;

    import org.apache.maven.plugin.descriptor.PluginDescriptor;

    import org.apache.maven.plugins.annotations.Component;

    import org.apache.maven.plugins.annotations.Execute;

    import org.apache.maven.plugins.annotations.InstantiationStrategy;

    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.plugins.annotations.ResolutionScope;

    import org.apache.maven.project.MavenProject;

    import org.apache.maven.settings.Settings;

           // 此Mojo对应的目标的名称

    @Mojo( name = "",

           aggregator = ,

           configurator = "",

           // 执行策略

           executionStrategy = "",

           inheritByDefault = ,

           // 实例化策略

           instantiationStrategy = InstantiationStrategy.,

           // 如果用户没有在POM中明确设置此Mojo绑定到的phase,那么绑定一个MojoExecution到那个phase

           defaultPhase = LifecyclePhase.,

           requiresDependencyResolution = ResolutionScope.,

           requiresDependencyCollection = ResolutionScope.,

           // 提示此Mojo需要被直接调用(而非绑定到生命周期阶段)

           requiresDirectInvocation = ,

           // 提示此Mojo不能在离线模式下运行

           requiresOnline = ,

           // 提示此Mojo必须在一个Maven项目内运行

           requiresProject = ,

           // 提示此Mojo是否线程安全,线程安全的Mojo支持在并行构建中被并发的调用

           threadSafe = ) // (since Maven 3.0)

    // 何时执行此Mojo

    @Execute( goal = "",           // 如果提供goal,则隔离执行此Mojo

              phase = LifecyclePhase., // 在此生命周期阶段自动执行此Mojo

              lifecycle = "" )  // 在此生命周期中执行此Mojo

    public class MyMojo

        extends AbstractMojo

    {

        

        @Parameter( name = "parameter",

                    // 在POM中可使用别名来配置参数

                    alias = "myAlias",

                    property = "a.property",

                    defaultValue = "an expression, possibly with ${variables}",

                    readonly = ,

                    required = )

        private String parameter;

        @Component( role = MyComponentExtension.class,

                    hint = "..." )

        private MyComponent component;

        @Parameter( defaultValue = "${session}", readonly = true )

        private MavenSession session;

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

        private MavenProject project;

        @Parameter( defaultValue = "${mojoExecution}", readonly = true )

        private MojoExecution mojo;

        @Parameter( defaultValue = "${plugin}", readonly = true )

        private PluginDescriptor plugin;

        @Parameter( defaultValue = "${settings}", readonly = true )

        private Settings settings;

        @Parameter( defaultValue = "${project.basedir}", readonly = true )

        private File basedir;

        @Parameter( defaultValue = "${project.build.directory}", readonly = true )

        private File target;

        public void execute()

        {

        }

    }

  • 相关阅读:
    NX二次开发-C++使用IDA Pro反编译dll,追踪查看里面使用的UFUN API函数(三部曲1)
    搭建企业社区,如何激发员工互动?
    刷新三观的HP-UX系统中的强指针赋值出core问题
    【学习笔记之Linux】云服务器搭建
    内核网络层的实现
    文件包含漏洞详解
    关于“非法的前向引用(illegal forward reference)”的探究
    一文快速了解「脉动调查」
    部署LVS-DR+Keepalived高可用群集构建
    mysql面试题(史上最全面试题,精心整理100家互联网企业,面试必过)
  • 原文地址:https://blog.csdn.net/yczz/article/details/128213261