<a name="lkFfi"></a>html
<br />众所周知,maven 实质上是一个插件执行框架,全部的工做都是经过插件完成的。包括咱们平常使用到的相似 install、clean、deploy、compiler。。。这些命令,其实底层都是一个一个的 maven 插件。<br />java
<a name="Vqcuo"></a>git
<a name="YXV79"></a>github
<br />在写一个项目以前,第一件事就是肯定一个名称。maven 插件也不例外。它有着本身的一套命名规范。可是规范很简单,一句话就能够归纳,**官方插件命名的格式为 maven-xxx-plugin,非官方的插件命名为 xxx-maven-plugin 。**是否是以为很眼熟,没错,spring boot starter 的命名也有相似的规范。<br /> <br />好的,咱们的第一个 maven 插件项目就叫 demo-maven-plugin 吧。<br />spring
<a name="GiT3p"></a>express
<br />名称起好了,下一步就是建立这个项目。若是你使用 idea 的话,那么建立十分的便捷,按以下步骤便可:<br />apache
<a name="KUkrj"></a>api
<br /><br />安全
<a name="C6Bwv"></a>session
<br /><br /> <br />点击 Next<br />
<a name="OuMCA"></a>
<br /><br />
<a name="J7V2Y"></a>
<a name="0Rro5"></a>
<br /><br />
能够看到生成的项目就是咱们最最多见的 maven 项目的结构,生成的文件也不多,一个 pom.xml 文件,一个 MyMojo 文件,简单介绍一下这两个文件
<a name="c1pG3"></a>
<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>cn.coder4j.study.example</groupId> <artifactId>demo-maven-plugin</artifactId> <packaging>maven-plugin</packaging> <version>1.0-SNAPSHOT</version> <name>demo-mavne-plugin Maven Mojo</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>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
首先生成的项目 pom.xml 中,自动依赖了两个项目,一个是 maven-plugin-api ,这个是开发 maven 插件必须依赖的核心包。另外一个是单元测试时使用的 junit 包。这两个没什么要注意的,真正要注意的是这个项目的 packaging,一般我遇到的 packaging 都是 jar、war、pom,这里比较特殊是 maven-plugin。
<a name="1Z2oD"></a>
package cn.coder4j.study.example; /* * Copyright 2001-2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import java.io.File; import java.io.FileWriter; import java.io.IOException; /** * 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 } } } } }
<br />首先生成的类继承了 AbstractMojo 这个抽象类,这里是 maven 插件的规范要求,maven 插件必需要继承 AbstractMojo 并实现他的 execute 方法。<br /> <br />另外能够看到类与方法使用了不少 tag。注意是 tag 而不是注解,注解是直接标记的,而 tag 是在文档注释里面的。<br /> <br />其中 @goal 这个 tag 的做用是指定插件的命名,好比咱们经常使用的 mvn clean,这个 clean 就是他的 @goal 。<br /> <br />而 @phase 是绑定插件执行的生成周期,好比你绑定在 clean 这个周期,那你在执行 clean 的时候会自动触发你的插件。<br /> <br />@parameter 用来指定插件的参数。<br /> <br />小朋友你是否有不少问号?tag 这个东西写在文档注释里面的东西,方即是方便可是容易写错呀,写错没有语法报错,写对时候也没有语法提示,为何不直接用注解的形式呢?缘由是 java 的注解是 jdk1.5 以后才有的,而实现 maven 的时候尚未这种语法。因此要一条路走到黑,一直背这个历史包袱吗?固然不是,后面咱们会说解决办法。另外,这种写法虽然不推荐使用了,可是有些 maven 的经典插件因为完成时间比较早,熟悉这些 tag 对于理解代码也有帮助。
<a name="POu8y"></a>
<a name="8Rtcq"></a>
<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>cn.coder4j.study.example</groupId> <artifactId>demo-maven-plugin</artifactId> <packaging>maven-plugin</packaging> <version>1.0-SNAPSHOT</version> <name>demo-mavne-plugin Maven Mojo</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>org.apache.maven</groupId> <artifactId>maven-plugin-api</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>org.apache.maven.plugin-tools</groupId> <artifactId>maven-plugin-annotations</artifactId> <version>3.5.2</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-plugin-plugin</artifactId> <version>3.5.2</version> </plugin> </plugins> </build> </project>
<br />相较于默认的 pom.xml 文件,咱们作了以下几个变更:<br />
<a name="sKZIC"></a>
/* * * * * * * * blog.coder4j.cn * * * Copyright (C) 2016-2020 All Rights Reserved. * * * */ package cn.coder4j.study.example; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; /** * @author buhao * @version DemoMojo.java, v 0.1 2020-03-30 22:51 buhao */ @Mojo(name = "hello") public class DemoMojo extends AbstractMojo { @Parameter(name = "name", defaultValue = "kiwi") private String name; public void execute() throws MojoExecutionException, MojoFailureException { getLog().info("hello " + name); } }
<br />首先,同生成的类同样,咱们的类必须继承 AbstractMojo 并实现他的 execute 方法,而 execute 方法其实就是这个插件的入口类。<br /> <br />示例代码中有两个很重要的注解,一个是 @Mojo ,它主要用来定义插件相关的信息至关于上面说的 @goal ,其中 name 属性用来指定这个插件名称,同 clean 相似。<br /> <br />另一个重要注解 @Parameter ,则是用来指定插件运行时使用的参数,其中 name 是参数名,defaultValue 顾名思义是默认值,也就是在用户没有设置的时候使用的值。<br /> <br />详细的插件及做用以下:<br />
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 = "<goal-name>", aggregator = <false|true>, configurator = "<role hint>", // 执行策略 executionStrategy = "<once-per-session|always>", inheritByDefault = <true|false>, // 实例化策略 instantiationStrategy = InstantiationStrategy.<strategy>, // 若是用户没有在POM中明确设置此Mojo绑定到的phase,那么绑定一个MojoExecution到那个phase defaultPhase = LifecyclePhase.<phase>, requiresDependencyResolution = ResolutionScope.<scope>, requiresDependencyCollection = ResolutionScope.<scope>, // 提示此Mojo须要被直接调用(而非绑定到生命周期阶段) requiresDirectInvocation = <false|true>, // 提示此Mojo不能在离线模式下运行 requiresOnline = <false|true>, // 提示此Mojo必须在一个Maven项目内运行 requiresProject = <true|false>, // 提示此Mojo是否线程安全,线程安全的Mojo支持在并行构建中被并发的调用 threadSafe = <false|true> ) // (since Maven 3.0) // 什么时候执行此Mojo @Execute( goal = "<goal-name>", // 若是提供goal,则隔离执行此Mojo phase = LifecyclePhase.<phase>, // 在今生命周期阶段自动执行此Mojo lifecycle = "<lifecycle-id>" ) // 在今生命周期中执行此Mojo public class MyMojo extends AbstractMojo { @Parameter( name = "parameter", // 在POM中可以使用别名来配置参数 alias = "myAlias", property = "a.property", defaultValue = "an expression, possibly with ${variables}", readonly = <false|true>, required = <false|true> ) 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() { } }
<br /> <br />回到示例上了,咱们这个插件做用很简单,根据配置输出 hello xxx,若是没有配置就输出 hello kiwi。咱们在写插件时,固然不会这样写,可是经过这个 demo,你就掌握了 maven 插件的大部分知识,能够本身作一些颇有趣的插件。<br />
<a name="NE3Km"></a>
<br />首先上面咱们的代码写完了,必需要 Install 一下,不然别的项目没法直接依赖,若是你还想给其它人使用,那还需上传到 maven 仓库。<br />
<a name="iSaux"></a>
<build> <plugins> <plugin> <groupId>cn.coder4j.study.example</groupId> <artifactId>demo-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> </plugin> </plugins> </build>
<br />在咱们想使用插件的项目中,添加如上配置,其中 plugin 中使用咱们插件的 GAV 信息。<br />
<a name="ljwip"></a>
<br /><br /> <br />若是上面配置的都正确,那么在 idea 右侧的 Maven 中,你配置的项目的 Plugins 下会多了一个 demo(具体根据你插件项目的名称),而 demo 里面会有一个 demo:hello,其中这个 demo 对应你插件项目的名称,而 hello 对应你插件的名称也就是 @Mojo 中的 name 。<br /> <br />好的,咱们双击一下,demo:hello ,会输出以下日志:<br /> <br />
<br /> <br />这样,咱们的第一个 Maven 插件就行了。<br />
<a name="dnDND"></a>
<br />可能你还记得,咱们在写 DemoMojo 的时候还指定了一个 name 属性,而且为它指定了一个 Parameter,这个如何使用。只要在依赖的插件下面添加 configuration 标签就能够了。<br />
<build> <plugins> <plugin> <groupId>cn.coder4j.study.example</groupId> <artifactId>demo-maven-plugin</artifactId> <version>1.0-SNAPSHOT</version> <configuration> <name>tom</name> </configuration> </plugin> </plugins> </build>
<br />其中 configuration 标签内的标签,对应你定义的参数名称,并且 idea 还有语法提示,很 nice。<br /> <br />好的,咱们再运行一下,结果以下:<br /> <br /><br /> <br />好的,大功告成。<br />
<a name="QGJPw"></a>
<a name="c1ftM"></a>
<br />Maven 插件开发
Maven 插件编写<br />
<a name="cwa1g"></a>
由于篇幅有限,没法贴完全部代码,如遇到问题可到 github 上查看源码。<br />
<a name="HTlMp"></a>
<br />
本文由博客一文多发平台 OpenWrite 发布!