大多数计算机语言的学习都是从Hello World开始,我们通过创建一个在控制台打印Hello World字符串的maven插件来学习如何开发一个自定义maven插件。
快速开发第一个插件
1,创建一个maven-plugin目录,并进入此目录。
2,运行命令:
mvn archetype:create -DgroupId=com.ailbaba.maven -DartifactId=maven-hello-plugin -DarchetypeArtifactId=maven-archetype-mojo
可以看到新建一个工程,其pom.xml:
<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>com.alibaba.maven</groupId>
<artifactId>maven-hello-plugin</artifactId>
<packaging>maven-plugin</packaging>
<version>1.0-SNAPSHOT</version>
<name>maven-hello-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>
3,进入maven-hello-plugin目录,运行命令:mvn eclipse:eclipse构建eclipse工程。
4,通过eclipse import工程,删除包下面自动生成的java文件,新建HelloWorldMojo.java,HelloWorldMojo.java的内容如下:
package com.alibaba.maven;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
/**
* @goal helloworld
*/
public class HelloWorldMojo extends AbstractMojo {
/**
* @parameter expression="${helloworld.words}" default-value="Hello World!"
*/
private String words;
public void execute() throws MojoExecutionException {
getLog().info(words);
}
}
5, 文件编写完成后回到cmd命令行,在项目的pom文件目录处运行install命令将插件安装到本地repository:mvn clean install
6, 安装成功后继续运行如下命令查看插件的运行情况:
运行:
mvn com.alibaba.maven:maven-hello-plugin:1.0-SNAPSHOT:helloworld
,可以看到控制台看到输出:"Hello World!";这个输出是插件的默认参数:
default-value="Hello World!"
运行
mvn com.alibaba.maven:maven-hello-plugin:1.0-SNAPSHOT:helloworld -Dhelloworld.words="welcome!"
可以在控制台看到输出:"welcome!";这个在命令中明确指定插件的参数,因此输出的是指定的参数"welcome!"。
关键点
1.maven的参数注入
maven默认使用的自行开发的Plexus,Plexus使用javadoc来管理依赖注入,可以看到上面的@goal,@parameter都是通过这种方式注入,现在看起来非常原始,不过maven3将迁移到guice.
2.MOJO
maven是由生命周期和goal完成任务的,比如maven install实际上包换了多种goal.插件中的每个任务goal称作一个 Mojo(Maven plain Old Java Object)。项目中每一个Mojo都要实现org.apache.maven.plugin.Mojo接口,上面的插件示例的Mojo通过扩展org.apache.maven.plugin.AbstractMojo类实现了该接口。Mojo提供如下的方法:
void setLog( org.apache.maven.monitor.logging.Log log)
当Maven加载并运行Mojo的时候,它会调用setLog()方法,为Mojo实例提供正确的日志目标。
Mojo接口只关心两件事情:目标运行结果的日志记录,以及运行一个目标。当编写自定义插件的时候,需要扩展AbstractMojo。 AbstractMojo处理setLog()和getLog()的实现,并包含一个抽象的execute()方法。在扩展AbstractMojo的时候,你所需要做的只是实现execute()方法。
公司maven-autoconfig-plugin探究
在你的本地仓库会有maven autoconfig插件的代码,svn地址:http://svn.alibaba-inc.com/repos/ali_platform/maven/plugins/maven-autoconf-plugin/trunk,可以看一下核心类AutoconfMojo,其实里面非常简单:
/**
* Autoconf Mojo, eg: mvn autoconf:autoconf
*
* @goal autoconf
* @requiresProject false
*
* @author shawn.qianx
* @author hongyuan.zhouhy
* @author william.liangf
*/
public class AutoconfMojo extends AbstractMojo {
/**
* directory or jar/war/zip archive path, separate by comma, default is current directory.
*
* @parameter expression="${path}"
*/
private String path;
public void execute() throws MojoExecutionException, MojoFailureException {
getLog().info("Execute autoconf:autoconf.");
WarConfigRuntimeImpl runtime = new WarConfigRuntimeImpl(System.in, System.out, System.err, charset);
if(path != null && path.trim().length() > 0){
runtime.setDests(path.split(","));
} else {
runtime.setDests(new String[] {"."});
}
if (charset == null) {
charset = ConfigConstant.DEFAULT_CHARSET;
}
if (encoding == null) {
encoding = ConfigConstant.DEFAULT_CHARSET;
}
if (interactive) {
getLog().info("Turn on interactive mode.");
runtime.setInteractiveMode(ConfigConstant.INTERACTIVE_ON);
}
if (gui) {
runtime.setGuiMode();
}
if (verbose) {
runtime.setVerbose();
}
if(properties != null && properties.trim().length() > 0){
getLog().info("Customized user properties:" + properties + " using encoding:" + charset);
runtime.setUserPropertiesFile(properties, charset);
}
if (userProp != null && userProp.trim().length() > 0) {
getLog().info("Customized user properties:" + userProp + " using encoding:" + encoding);
runtime.setUserPropertiesFile(userProp, encoding);
}
if (sharedProperties != null && sharedProperties.length() > 0) {
getLog().info("Customized shared properties: " + descriptors);
runtime.setSharedPropertiesFiles(sharedProperties.split(","), sharedPropertiesName, charset);
}
if ((descriptors != null && descriptors.length() > 0)
|| (excludeDescriptors != null && excludeDescriptors.length() > 0)) {
String[] includes;
String[] excludes;
PatternSet patterns = runtime.getDescriptorPatterns();
if (descriptors == null || descriptors.length() == 0) {
try {
includes = patterns.getIncludes();
} catch (NullPointerException npe) {
includes = new String[0];
}
} else {
getLog().info("Customized include descriptors: " + descriptors);
includes = descriptors.split(",");
}
if (excludeDescriptors == null || excludeDescriptors.length() == 0) {
try {
excludes = patterns.getExcludes();
} catch (NullPointerException npe) {
excludes = new String[0];
}
} else {
getLog().info("Customized exclude descriptors: " + excludeDescriptors);
excludes = excludeDescriptors.split(",");
}
runtime.setDescriptorPatterns(includes, excludes);
}
if ((packages != null && packages.length() > 0)
|| (excludePackages != null && excludePackages.length() > 0)) {
String[] includes;
String[] excludes;
PatternSet patterns = runtime.getPackagePatterns();
if (packages == null || packages.length() == 0) {
try {
includes = patterns.getIncludes();
} catch (NullPointerException npe) {
includes = new String[0];
}
} else {
getLog().info("Customized include packages: " + descriptors);
includes = packages.split(",");
}
if (excludePackages == null || excludePackages.length() == 0) {
try {
excludes = patterns.getExcludes();
} catch (NullPointerException npe) {
excludes = new String[0];
}
} else {
getLog().info("Customized exclude packages: " + excludeDescriptors);
excludes = excludePackages.split(",");
}
runtime.setPackagePatterns(includes, excludes);
}
try {
runtime.start();
} catch (Exception e) {
runtime.error(e);
throw new MojoExecutionException("autoconf execution error", e);
}
}
}
小结
开发一个maven插件就是开发一个mojo,然后这样使用它们:maven xx:xx 。