前言
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
,default
和report
,不同的生命周期中提供了一些快捷的操作命令給開(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)了setLog
和getLog
方法碑韵,只留下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
(二)驗(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ǔ)句。
方式二:把自定義插件綁定在項(xiàng)目的生命周期中
如果我們的自定義插件是希望在打包的過(guò)程某個(gè)固定的生命周期發(fā)生作用腊嗡,那么我們可以在pom文件中把插件綁定在我們項(xiàng)目的生命周期中着倾。
插件寫(xiě)在build->plugins->plugin標(biāo)簽下,groupId
這些信息和插件保持一直燕少,然后需要在executions
標(biāo)簽中定義我們這個(gè)使用這個(gè)自定義插件的哪個(gè)能力卡者,也就是goal
,phase
標(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é)果
我們可以看到恒傻,我們的自定義插件順利隨著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=moutory
Java可以將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
為我們想要配置的值谅辣。
以下面的配置為例修赞,我們分別為userName
和status
配置不同的值:
<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é)果
方式二:maven命令傳參
這種方式比較適用于那些獨(dú)立使用的插件桑阶,比如代碼掃描工具或者依賴(lài)掃描插件柏副。使用maven命令傳參也十分簡(jiǎn)單,在命令后面使用-Dkey=value
蚣录。這里的key
為@property
中配置的property
屬性的值割择,value
為我們實(shí)際傳入的值。對(duì)應(yīng)到我們上面的案例萎河,這里的參數(shù)就可以是-Dtimer.username=Tonny -Dtimer.status=bad
荔泳。
(二)插件中可以接收的參數(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
,他的groupId
是org.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
通過(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
從日志上面來(lái)看师枣,war包已經(jīng)復(fù)制成功了,那么切換到對(duì)應(yīng)的webapp
目錄上面萧落,也可以看到践美,war包確實(shí)已經(jīng)復(fù)制過(guò)來(lái)了。
總結(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
最后,也要十分感謝參考文章中的作者颖榜,他詳盡的文章給了我很大的幫助棚饵,也十分推薦各位讀者去看看這篇文章。