maven進(jìn)階——開(kāi)發(fā)自定義插件

前言

maven不僅僅只是項(xiàng)目的依賴(lài)管理工具刀脏,其強(qiáng)大的核心來(lái)源自豐富的插件吁朦,可以說(shuō)插件才是maven工具的靈魂。本篇文章將對(duì)如何自定義maven插件進(jìn)行講解甸饱,希望對(duì)各位讀者有所幫助联四。

知識(shí)背景

什么是maven插件撑碴?
講如何開(kāi)發(fā)maven插件之前,不妨先來(lái)聊一下什么是maven的插件朝墩。

我們知道醉拓,maven中主要有三大生命周期,clean,defaultreport,不同的生命周期中提供了一些快捷的操作命令給開(kāi)發(fā)人員去進(jìn)行項(xiàng)目的清理亿卤、編譯愤兵、打包等操作。之所以我們可以通過(guò)類(lèi)似于mvn clean compile等命令快速完成項(xiàng)目的清理和構(gòu)建排吴,實(shí)際上是因?yàn)閙aven在項(xiàng)目核心的生命周期節(jié)點(diǎn)上秆乳,已經(jīng)設(shè)置好了默認(rèn)的運(yùn)行插件,我們執(zhí)行命令的時(shí)候傍念,實(shí)際上調(diào)用的就是綁定對(duì)應(yīng)生命周期的插件矫夷。
maven插件本質(zhì)上就是一個(gè)jar包葛闷,不同的插件里面有著不同功能的代碼憋槐,當(dāng)我們調(diào)用該插件的時(shí)候,其實(shí)就是通過(guò)執(zhí)行jar包中的方法淑趾,去達(dá)到對(duì)應(yīng)的goal阳仔,實(shí)現(xiàn)我們的目的。除了官網(wǎng)的maven插件之外扣泊,其實(shí)maven還允許我們根據(jù)實(shí)際的項(xiàng)目需要近范,自定義去開(kāi)發(fā)maven插件,從而滿足我們的項(xiàng)目構(gòu)建需要延蟹。

關(guān)于maven的生命周期和插件评矩,我們可以從官方文檔中了解更多信息:
maven的生命周期:https://maven.apache.org/ref/3.8.6/maven-core/lifecycles.html
maven生命周期綁定的默認(rèn)插件:https://maven.apache.org/ref/3.8.6/maven-core/default-bindings.html

一、自定義插件demo開(kāi)發(fā)

(一)開(kāi)發(fā)自定義插件
步驟一:配置pom文件

我們先在idea中創(chuàng)建一個(gè)maven項(xiàng)目阱飘,并在pom文件中寫(xiě)入如下配置斥杜,這里的目的是標(biāo)識(shí)我們這個(gè)項(xiàng)目是maven插件項(xiàng)目,需要按照插件的方式來(lái)進(jìn)行打包沥匈。

<packaging>maven-plugin</packaging>

其次蔗喂,引入插件開(kāi)發(fā)所需要的依賴(lài),這里版本不一定需要和我一致高帖,只要兩個(gè)依賴(lài)之前版本不要差距過(guò)大就行缰儿。

         <!--這個(gè)依賴(lài)引入了插件開(kāi)發(fā)需要的相關(guān)基礎(chǔ)類(lèi)-->
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>3.0</version>
        </dependency>
         <!--這個(gè)依賴(lài)引入了插件開(kāi)發(fā)需要的相關(guān)注解-->
        <dependency>
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>3.4</version>
            <scope>provided</scope>
        </dependency>
步驟二:定義插件類(lèi)

我們上一個(gè)步驟已經(jīng)在pom文件中定義了我們這個(gè)項(xiàng)目是一個(gè)maven插件類(lèi)型的項(xiàng)目沸版,而maven插件是需要對(duì)外提供各種實(shí)際應(yīng)用能力的尤泽,在這個(gè)步驟中,我們將定義我們這個(gè)插件對(duì)外提供的實(shí)際能力惭笑,這樣其他項(xiàng)目想要使用我們插件的時(shí)候预麸,就可以選擇對(duì)應(yīng)的goal來(lái)執(zhí)行了义起。
PS:需要注意的是,一個(gè)插件是可以同時(shí)提供多種能力的师崎,但本案例只作為演示所以只會(huì)寫(xiě)一個(gè)功能作

1默终、定義插件類(lèi)的2種方式

定義插件類(lèi)有2種方式,第一種是創(chuàng)建java類(lèi),實(shí)現(xiàn)org.apache.maven.plugin.Mojo接口齐蔽。

void execute() throws MojoExecutionException, MojoFailureException;
void setLog( Log log );
Log getLog();

這個(gè)接口一共定義了三個(gè)接口方法:

  • execute 這個(gè)方法為核心方法两疚,當(dāng)使用mvn命令調(diào)用插件的目標(biāo)的時(shí)候,最后具體調(diào)用的就是這個(gè)方法
  • setLog:注入一個(gè)標(biāo)準(zhǔn)的Maven日志記錄器含滴,允許這個(gè)Mojo向用戶(hù)傳遞事件和反饋
  • getLog:獲取注入的日志記錄器

一般來(lái)說(shuō)诱渤,我們并不會(huì)直接通過(guò)實(shí)現(xiàn)接口的方式來(lái)定義插件,而是會(huì)采用繼承maven提供的抽象類(lèi)org.apache.maven.plugin.AbstractMojo來(lái)定義我們的插件類(lèi)谈况。

public abstract class AbstractMojo implements Mojo, ContextEnabled {
         ...
}

我們可以看到勺美,這個(gè)抽象類(lèi)實(shí)現(xiàn)了Mojo接口,同時(shí)這個(gè)抽象類(lèi)還實(shí)現(xiàn)了setLoggetLog方法碑韵,只留下execute方法給開(kāi)發(fā)人員去實(shí)現(xiàn)赡茸。這個(gè)類(lèi)中Log默認(rèn)可以向控制臺(tái)輸出日志信息,maven中自帶的插件都繼承這個(gè)類(lèi)祝闻,一般情況下我們開(kāi)發(fā)插件目標(biāo)可以直接繼承這個(gè)類(lèi)占卧,然后實(shí)現(xiàn)execute方法就可以了。

2联喘、在我們的代碼中進(jìn)行實(shí)操

在剛剛創(chuàng)建的插件項(xiàng)目中华蜒,創(chuàng)建一個(gè)普通的java類(lèi),繼承org.apache.maven.plugin.AbstractMojo這個(gè)抽象類(lèi)豁遭,同時(shí)需要在類(lèi)上面使用@Mojo注解叭喜。這樣maven在執(zhí)行我們的插件的時(shí)候,才能夠找到我們的入口類(lèi)蓖谢。

在execute方法中捂蕴,我們簡(jiǎn)單地打印一句話到控制臺(tái)

@Mojo(name = "TimerPlugin")
public class TimerPlugin extends AbstractMojo {

    public void execute() throws MojoExecutionException, MojoFailureException {
        String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        getLog().info("timer plugin is running,current time is " + currentTime);
    }
}
步驟三:將我們的插件上傳到我們的本地倉(cāng)庫(kù)

執(zhí)行如下maven命令實(shí)現(xiàn)插件的上傳蜈抓,打包完成后我們就可以在我們本地倉(cāng)庫(kù)中找到我們的插件了启绰。

mvn clean install
image.png
(二)驗(yàn)證插件

插件開(kāi)發(fā)成功后,我們可以有2種方式來(lái)使用我們的自定義插件

方式一:直接通過(guò)maven命令(我們?cè)诘谌轮袝?huì)詳細(xì)講一下這個(gè)maven命令的使用)

maven命令的格式如下:

mvn 插件groupId:插件artifactId[:插件版本]:插件目標(biāo)名稱(chēng)

對(duì)應(yīng)我們的案例沟使,執(zhí)行的命令即為mvn com.qiqv:timer-plugin-demo:TimerPlugin委可,執(zhí)行命令后可以看到控制臺(tái)中就已經(jīng)出現(xiàn)了我們插件中打印的語(yǔ)句。

image.png
方式二:把自定義插件綁定在項(xiàng)目的生命周期中

如果我們的自定義插件是希望在打包的過(guò)程某個(gè)固定的生命周期發(fā)生作用腊嗡,那么我們可以在pom文件中把插件綁定在我們項(xiàng)目的生命周期中着倾。

插件寫(xiě)在build->plugins->plugin標(biāo)簽下,groupId這些信息和插件保持一直燕少,然后需要在executions標(biāo)簽中定義我們這個(gè)使用這個(gè)自定義插件的哪個(gè)能力卡者,也就是goalphase標(biāo)簽里面定義要綁定的生命周期客们,id用于命令崇决,可以自己定義材诽。

    <build>
        <plugins>
            <plugin>
                <groupId>com.qiqv</groupId>
                <artifactId>timer-plugin-demo</artifactId>
                <version>1.0.0</version>
                <executions>
                    <execution>
                        <id>test</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>TimerPlugin</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

在外部項(xiàng)目中綁定好插件后,我們通過(guò)mvn compile命令看一下結(jié)果

執(zhí)行結(jié)果

我們可以看到恒傻,我們的自定義插件順利隨著compile生命周期執(zhí)行了脸侥。

二、插件傳參

在第一章中盈厘,我們已經(jīng)簡(jiǎn)單實(shí)現(xiàn)了一個(gè)maven插件睁枕,但實(shí)際上這種沒(méi)有任何參數(shù)的插件一般來(lái)說(shuō)很難支持比較復(fù)雜、靈活的功能沸手。所以這一章中外遇,我們將學(xué)習(xí)如何把參數(shù)傳遞給我們的插件。

(一)在Mojo類(lèi)中定義我們接收數(shù)據(jù)的參數(shù)

延續(xù)第一章的例子契吉,我們?cè)诓寮?lèi)中定義2個(gè)變量跳仿,并加上@Paramter注解,這個(gè)注解將變量標(biāo)識(shí)為mojo參數(shù)栅隐。注解的defaultValue參數(shù)定義變量的默認(rèn)值塔嬉。property參數(shù)可用于通過(guò)引用用戶(hù)通過(guò)-D選項(xiàng)設(shè)置的系統(tǒng)屬性玩徊,即通過(guò)從命令行配置mojo參數(shù)租悄,如mvn ... -Dtimer.username=moutoryJava可以將moutory的值傳遞給userName參數(shù)。

當(dāng)然了恩袱,如果說(shuō)不打算通過(guò)命令行執(zhí)行泣棋,只想傳參給和生命周期綁定的插件,那么也需要要加上注解畔塔,注解里面可以不用配置其他屬性潭辈。

@Mojo(name = "TimerPlugin")
public class TimerPlugin extends AbstractMojo {

    @Parameter(property = "timer.username" ,defaultValue = "moutory")
    private String userName;

    @Parameter(property = "timer.status", defaultValue = "happy")
    private String status;

    public void execute() throws MojoExecutionException, MojoFailureException {
        String currentTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        getLog().info("timer plugin is running, current time is " + currentTime);
        getLog().info(String.format("hi %s ! Now you are %s",userName,status));
    }
}
(二)在使用中向我們的插件傳遞參數(shù)
方式一:在pom文件進(jìn)行定義

這種做法一般是用于和生命周期綁定使用的插件,我們可以在配置插件的時(shí)候,利用configuration標(biāo)簽來(lái)配置我們插件的值澈吨。configuration標(biāo)簽內(nèi)可以寫(xiě)入我們想要配置的參數(shù)把敢,標(biāo)簽的key為我們插件定義的屬性名,標(biāo)簽的value為我們想要配置的值谅辣。

以下面的配置為例修赞,我們分別為userNamestatus配置不同的值:

 <build>
        <plugins>
            <plugin>
                <groupId>com.qiqv</groupId>
                <artifactId>timer-plugin-demo</artifactId>
                <version>1.0.0</version>
                <executions>
                    <execution>
                        <id>test</id>
                        <phase>compile</phase>
                        <goals>
                            <goal>TimerPlugin</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <userName>Jim</userName>
                    <status>good</status>
                </configuration>
            </plugin>
        </plugins>
    </build>

使用mvn compile命令,看一下執(zhí)行的結(jié)果

image.png

方式二:maven命令傳參

這種方式比較適用于那些獨(dú)立使用的插件桑阶,比如代碼掃描工具或者依賴(lài)掃描插件柏副。使用maven命令傳參也十分簡(jiǎn)單,在命令后面使用-Dkey=value蚣录。這里的key@property中配置的property屬性的值割择,value為我們實(shí)際傳入的值。對(duì)應(yīng)到我們上面的案例萎河,這里的參數(shù)就可以是-Dtimer.username=Tonny -Dtimer.status=bad荔泳。

使用maven命令傳參
(二)插件中可以接收的參數(shù)類(lèi)型

除了String類(lèi)型蕉饼,自定義插件還可以接收其他多種參數(shù)類(lèi)型,下面就對(duì)這些參數(shù)進(jìn)行簡(jiǎn)單的介紹玛歌。

1椎椰、boolean類(lèi)型
@Parameter
private boolean myBoolean;
<configuration>
      <myBoolean>true</myBoolean>
</configuration>
2、數(shù)字類(lèi)型

數(shù)字類(lèi)型包含:byte, Byte, int, Integer, long, Long, short, Short沾鳄,讀取配置時(shí)慨飘,XML文件中的文本將使用適當(dāng)類(lèi)的integer.parseInt()valueOf()方法轉(zhuǎn)換為整數(shù)值,這意味著字符串必須是有效的十進(jìn)制整數(shù)值译荞,僅由數(shù)字0到9組成瓤的,前面有一個(gè)可選的-表示負(fù)值。

@Parameter
private Integer myNum;
<configuration>
      <myNum>2</myNum>
</configuration>
3吞歼、File類(lèi)型參數(shù)

讀取配置時(shí)圈膏,XML文件中的文本用作所需文件或目錄的路徑。如果路徑是相對(duì)的(不是以/或C:之類(lèi)的驅(qū)動(dòng)器號(hào)開(kāi)頭)篙骡,則路徑是相對(duì)于包含POM的目錄的

@Parameter
private File myFile;
<configuration>
      <myFile>C:\test</myFile>
</configuration>
4稽坤、枚舉類(lèi)型參數(shù)
public enum Color {
      GREEN,
      RED,
      BLUE
}
/**
* My Enum
*/
@Parameter
private Color myColor;
<myColor>GREEN</myColor>
5、數(shù)組類(lèi)型參數(shù)
@Parameter
private String[] myArr;
<configuration>
      <myArr>
           <param>aa</param>
           <param>bb</param>
     </myArr>
</configuration>
6糯俗、Collections類(lèi)型參數(shù)

和數(shù)組類(lèi)型參數(shù)用法一樣

7尿褪、Maps類(lèi)型參數(shù)
@Parameter
private Map myMap;
<configuration>
   <myMap>
         <key1>value1</key1>
        <key2>value2</key2>
   </myMap>
</configuration>
8、Properties類(lèi)型參數(shù)
@Parameter
private Properties myProperties;
<myProperties>
  <property>
    <name>propertyName1</name>
    <value>propertyValue1</value>
  <property>
  <property>
    <name>propertyName2</name>
    <value>propertyValue2</value>
  <property>
</myProperties>
9得湘、自定義類(lèi)型參數(shù)
@Parameter
private MyObject myObject;
<myObject>
  <myField>test</myField>
</myObject>

三杖玲、自定義插件前綴的使用

理論上我們開(kāi)發(fā)自定義插件時(shí),artifactId是可以隨便寫(xiě)淘正,并沒(méi)有嚴(yán)格的書(shū)寫(xiě)規(guī)定摆马。但即使把artifactId定義得比較短,我們?cè)谕ㄟ^(guò)命令使用插件時(shí)鸿吆,還是不得不敲上一長(zhǎng)串的命令囤采,無(wú)法像mvn clean這些官方插件一樣,使用很簡(jiǎn)單的命令就可以完成操作惩淳。出于簡(jiǎn)化命令的目的蕉毯,其實(shí)maven官方已經(jīng)定義一套插件命名規(guī)范,只要滿足這套命名規(guī)范黎泣,就可以在執(zhí)行命令的時(shí)候簡(jiǎn)化我們的語(yǔ)法恕刘。

若自定義插件的artifactId滿足下面的格式:

xxx-maven-plugin

如果采用這種格式的maven會(huì)自動(dòng)將xxx指定為插件的前綴,其他格式也可以抒倚,不過(guò)此處我們只說(shuō)這種格式褐着,這個(gè)是最常用的格式。

比如我們上面自定義插件改為timer-maven-plugin托呕,他的前綴就是timer含蓉。
當(dāng)我們配置了插件前綴频敛,可以插件前綴來(lái)調(diào)用插件的目標(biāo)了,命令如下:

mvn 插件前綴:插件目標(biāo)

但是上面的命令支提供了插件前綴馅扣,那么maven是如何知道對(duì)應(yīng)的groupId的呢斟赚?

maven默認(rèn)會(huì)在倉(cāng)庫(kù)"org.apache.maven.plugins" 和 "org.codehaus.mojo"2個(gè)位置查找插件,比如:
mvn clean:help差油。這個(gè)是調(diào)用maven-clean-plugin插件的help目標(biāo)拗军,maven-clean-plugin的前綴就是clean,他的groupIdorg.apache.maven.plugins蓄喇,所以能夠直接找到发侵。

但是我們自己定義的插件,如果也讓maven能夠找到妆偏,需要下面的配置:
~/.m2/settings.xml中配置自定義插件組刃鳄,我們需要在pluginGroups中加入自定義的插件組groupId,如:

<pluginGroup>com.qiqv</pluginGroup>

這樣當(dāng)我們通過(guò)前綴調(diào)用插件的時(shí)候钱骂,maven除了會(huì)在2個(gè)默認(rèn)的組中查找叔锐,還會(huì)在這些自定義的插件組中找,一般情況下我們自定義的插件通常使用同樣的groupId见秽。
當(dāng)我們配置了上面的自定義插件組后愉烙,我們就可以改為用下面的命令來(lái)調(diào)用我們的自定義插件了。

mvn timer:TimerPlugin
使用簡(jiǎn)化命令調(diào)用我們的插件

通過(guò)上面這種方式张吉,我們就可以實(shí)現(xiàn)用簡(jiǎn)化命令來(lái)調(diào)用我們的插件啦~~下面是需要額外注意的事項(xiàng):
1齿梁、官方的插件命名一般是maven-xxx-plugin催植,第三方的自定義插件命名一般是xxx-maven-plugin肮蛹,我們的命名規(guī)范盡量不要和官方插件的一致。
2创南、如果不想配置settings.xml這么麻煩伦忠,也可以直接在命令中加上groupId,這樣也可以讓maven可以找到你的自定義插件稿辙。

四昆码、開(kāi)發(fā)一個(gè)功能性更強(qiáng)的自定義組件

通過(guò)前面三章的介紹,其實(shí)我們已經(jīng)能夠掌握自定義插件開(kāi)發(fā)的大部分知識(shí)了邻储,接下來(lái)我們就以開(kāi)發(fā)功能性更強(qiáng)的插件為例赋咽,來(lái)作為收尾的一個(gè)小案例。
對(duì)一些web項(xiàng)目來(lái)說(shuō)吨娜,打包完之后我們需要把war包部署到tomcat上面進(jìn)行部署脓匿,每次都需要手動(dòng)復(fù)制包十分的麻煩,我們不妨嘗試著自己開(kāi)發(fā)一個(gè)插件宦赠,來(lái)解決這個(gè)場(chǎng)景的問(wèn)題陪毡。
(當(dāng)然了米母,現(xiàn)在idea都有這種自動(dòng)部署的功能,但作為學(xué)習(xí)的案例毡琉,自己手動(dòng)實(shí)現(xiàn)一下這個(gè)功能也是十分有意思的)

步驟一:創(chuàng)建一個(gè)新的插件項(xiàng)目铁瞒,定義pom文件

這一步和之前的并沒(méi)有什么區(qū)別,還是定義項(xiàng)目的打包類(lèi)型以及相關(guān)依賴(lài)

<packaging>maven-plugin</packaging>
    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>3.0</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>3.4</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
步驟二:創(chuàng)建插件的核心執(zhí)行類(lèi)

這里的話沒(méi)有寫(xiě)的很復(fù)雜桅滋,插件使用者提供一下war包位置慧耍,tomcat路徑以及最終的文件名,插件做一下簡(jiǎn)單的IO而已丐谋。

@Mojo(name="deploy")
public class DeployPlugin extends AbstractMojo {
    @Parameter
    private String sourceWarPath;
    @Parameter
    private String tomcatHome;
    @Parameter
    private String targetFileName;

    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {
        this.getLog().info("deploy plugin starting...");
        this.getLog().info("sourceWarPath:[{"+sourceWarPath+"}] , tomcatHome:[{"+tomcatHome+"}]");
        boolean cpSuccess = this.deployFile(sourceWarPath, tomcatHome, targetFileName);
        if(cpSuccess){
            this.getLog().info("deploy success");
            return;
        }
        this.getLog().error("deploy fail");
    }

    private boolean deployFile(String sourceWarPath, String tomcatHome,String targetFileName) {
        if(StringUtils.isBlank(sourceWarPath) || StringUtils.isBlank(tomcatHome)){
            throw new RuntimeException("missing required param!");
        }
        InputStream inputS = null;
        OutputStream outputS = null;
        String targetWarPath = tomcatHome + File.separator +"webapps"  + File.separator + targetFileName;

        // 通過(guò) String 創(chuàng)建文件
        try{
            File destF = new File(targetWarPath);
            File srcF = new File(sourceWarPath);

            // 通過(guò) File 創(chuàng)建 文件流
            inputS = new FileInputStream(srcF);
            outputS = new FileOutputStream(destF);

            // 讀寫(xiě)流
            byte[] buffer = new byte[1024];
            int length = 0;
            while ((length = inputS.read(buffer)) > 0) {
                outputS.write(buffer, 0, length);
            }
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }finally {
            closeIO(inputS,outputS);
        }
        return true;
    }

    private void closeIO(InputStream inputS, OutputStream outputS) {
        // 關(guān)閉流
        if(inputS != null){
            try{
                inputS.close();
            }catch (Exception e){
                this.getLog().error("close input stream fail..");
                e.printStackTrace();
            }
        }
        if(outputS != null){
            try{
                outputS.close();
            }catch (Exception e){
                this.getLog().error("close output stream fail..");
                e.printStackTrace();
            }
        }
    }
}

步驟三:在我們的其他項(xiàng)目引入我們的插件

這里需要注意蜂绎,除了需要傳參之外,還需要把插件綁定在package的生命周期

    <build>
        <plugins>
            <plugin>
                <groupId>com.qiqv</groupId>
                <artifactId>webDeploy-maven-plugin</artifactId>
                <version>1.0-SNAPSHOT</version>
                <executions>
                    <execution>
                        <id>test</id>
                        <phase>package</phase>
                        <goals>
                            <goal>deploy</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <sourceWarPath>D:\devWorkPlace\devCode\mime\maven-plugin\order-api\target\order-api-1.0-SNAPSHOT.war</sourceWarPath>
                    <tomcatHome>D:\devWorkPlace\devTool\apache-tomcat-9.0.68</tomcatHome>
                    <targetFileName>order-api-1.0-SNAPSHOT.war</targetFileName>
                </configuration>
            </plugin>
        </plugins>
    </build>
步驟四:項(xiàng)目打包笋鄙,觀察插件的運(yùn)行日志:
mvn package
插件執(zhí)行日志

從日志上面來(lái)看师枣,war包已經(jīng)復(fù)制成功了,那么切換到對(duì)應(yīng)的webapp目錄上面萧落,也可以看到践美,war包確實(shí)已經(jīng)復(fù)制過(guò)來(lái)了。

執(zhí)行效果圖

總結(jié)

這篇文章我們對(duì)maven自定義插件的開(kāi)發(fā)方法進(jìn)行了介紹找岖,了解插件的參數(shù)如何傳遞以及不同的參數(shù)如何傳遞陨倡,并配合兩個(gè)簡(jiǎn)單的案例來(lái)進(jìn)行講解⌒聿迹總的來(lái)說(shuō)兴革,自定義插件的開(kāi)發(fā)并不復(fù)雜,掌握了基本知識(shí)后蜜唾,難度其實(shí)在于插件所要實(shí)現(xiàn)的具體功能杂曲,后期有時(shí)間了我們可以出一期文章來(lái)分析某些優(yōu)秀的開(kāi)源maven插件是怎么實(shí)現(xiàn)的。

本篇文章的源碼袁余,可以從我的gitee上面獲取擎勘,地址如下:https://gitee.com/moutory/maven-plugin-demo
最后,也要十分感謝參考文章中的作者颖榜,他詳盡的文章給了我很大的幫助棚饵,也十分推薦各位讀者去看看這篇文章。

參考文章:

自定義插件掩完,Maven的生命交給你來(lái)設(shè)計(jì)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末噪漾,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子且蓬,更是在濱河造成了極大的恐慌欣硼,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缅疟,死亡現(xiàn)場(chǎng)離奇詭異分别,居然都是意外死亡遍愿,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)耘斩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)沼填,“玉大人,你說(shuō)我怎么就攤上這事括授∥塍希” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵荚虚,是天一觀的道長(zhǎng)薛夜。 經(jīng)常有香客問(wèn)我,道長(zhǎng)版述,這世上最難降的妖魔是什么梯澜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮渴析,結(jié)果婚禮上晚伙,老公的妹妹穿的比我還像新娘。我一直安慰自己俭茧,他們只是感情好咆疗,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著母债,像睡著了一般午磁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上毡们,一...
    開(kāi)封第一講書(shū)人閱讀 51,554評(píng)論 1 305
  • 那天迅皇,我揣著相機(jī)與錄音,去河邊找鬼漏隐。 笑死喧半,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的青责。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼取具,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼脖隶!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起暇检,我...
    開(kāi)封第一講書(shū)人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤产阱,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后块仆,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體构蹬,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡王暗,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了庄敛。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片俗壹。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖藻烤,靈堂內(nèi)的尸體忽然破棺而出绷雏,到底是詐尸還是另有隱情,我是刑警寧澤怖亭,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布涎显,位于F島的核電站,受9級(jí)特大地震影響兴猩,放射性物質(zhì)發(fā)生泄漏期吓。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一倾芝、第九天 我趴在偏房一處隱蔽的房頂上張望膘婶。 院中可真熱鬧,春花似錦蛀醉、人聲如沸悬襟。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)脊岳。三九已至,卻和暖如春垛玻,著一層夾襖步出監(jiān)牢的瞬間割捅,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工帚桩, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留亿驾,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓账嚎,卻偏偏與公主長(zhǎng)得像莫瞬,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子郭蕉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355