#Maven插件基本原理
##一、什么是maven插件
Maven 是一个执行插件的框架,每一个任务实际上是由插件完成的。Maven 插件通常用于:
创建 jar 文件
创建 war 文件
编译代码文件
进行代码单元测试
创建项目文档
创建项目报告
一个插件通常提供了一组目标,可使用以下语法来执行:
mvn [plugin-name]:[goal-name]
例如,一个 Java 项目可以使用 Maven 编译器插件来编译目标,通过运行以下命令编译
mvn compiler:compile
##二、maven插件类型
Maven 提供以下两种类型插件:
类型 描述
构建插件 在生成过程中执行,并在 pom.xml 中的 build元素进行配置
报告插件 在网站生成期间执行,在 pom.xml 中的 reporting 元素进行配置
以下是一些常见的插件列表:
插件 描述
clean 编译后的清理目标,删除目标目录
compiler 编译 Java 源文件
surefile 运行JUnit单元测试,创建测试报告
jar 从当前项目构建 JAR 文件
war 从当前项目构建 WAR 文件
javadoc 产生用于该项目的 Javadoc
antrun 从构建所述的任何阶段运行一组 Ant 任务
##三、maven插件原理
maven通过为某一个项目的生命周期阶段绑定若干个Mojo,然后依次执行Mojo.execute()方法,从而实现特定生命周期应该执行的动作。
例如
Mojo( name = "resources", defaultPhase = LifecyclePhase.PROCESS_RESOURCES, threadSafe = true )
public class ResourcesMojo
extends AbstractMojo
implements Contextualizable
{
/**
下面若干个attribute ,maven 读取pom.xml内的配置信息,这里的attribute对应着pom.xml里的配置,如果在这里声明了,maven在创建Mojo 实例
instance的时候,会将这些值注入到instance内,供Mojo instance使用
*/
/**
* The character encoding scheme to be applied when filtering resources.
*/
@Parameter( property = "encoding", defaultValue = "${project.build.sourceEncoding}" )
protected String encoding;
/**
* The output directory into which to copy the resources.
*/
@Parameter( defaultValue = "${project.build.outputDirectory}", required = true )
private File outputDirectory;
/**
* The list of resources we want to transfer.
*/
@Parameter( defaultValue = "${project.resources}", required = true, readonly = true )
private List resources;
/**
*
*/
@Parameter( defaultValue = "${project}", required = true, readonly = true )
protected MavenProject project;
/**
* The list of additional filter properties files to be used along with System and project
* properties, which would be used for the filtering.
*
* See also: {@link ResourcesMojo#filters}.
*
* @since 2.4
*/
@Parameter( defaultValue = "${project.build.filters}", readonly = true )
protected List buildFilters;
/**
* The list of extra filter properties files to be used along with System properties,
* project properties, and filter properties files specified in the POM build/filters section,
* which should be used for the filtering during the current mojo execution.
*
* Normally, these will be configured from a plugin's execution section, to provide a different
* set of filters for a particular execution. For instance, starting in Maven 2.2.0, you have the
* option of configuring executions with the id's
default-resources
and
*
default-testResources
to supply different configurations for the two
* different types of resources. By supplying
extraFilters
configurations, you
* can separate which filters are used for which type of resource.
*/
@Parameter
protected List filters;
/**
* If false, don't use the filters specified in the build/filters section of the POM when
* processing resources in this mojo execution.
*
* See also: {@link ResourcesMojo#buildFilters} and {@link ResourcesMojo#filters}
*
* @since 2.4
*/
@Parameter( defaultValue = "true" )
protected boolean useBuildFilters;
/**
*
*/
@Component( role = MavenResourcesFiltering.class, hint = "default" )
protected MavenResourcesFiltering mavenResourcesFiltering;
/**
*
*/
@Parameter( defaultValue = "${session}", required = true, readonly = true )
protected MavenSession session;
/**
* Expression preceded with the String won't be interpolated
* \${foo} will be replaced with ${foo}
*
* @since 2.3
*/
@Parameter( property = "maven.resources.escapeString" )
protected String escapeString;
/**
* Overwrite existing files even if the destination files are newer.
*
* @since 2.3
*/
@Parameter( property = "maven.resources.overwrite", defaultValue = "false" )
private boolean overwrite;
/**
* Copy any empty directories included in the Resources.
*
* @since 2.3
*/
@Parameter( property = "maven.resources.includeEmptyDirs", defaultValue = "false" )
protected boolean includeEmptyDirs;
/**
* Additional file extensions to not apply filtering (already defined are : jpg, jpeg, gif, bmp, png)
*
* @since 2.3
*/
@Parameter
protected List nonFilteredFileExtensions;
/**
* Whether to escape backslashes and colons in windows-style paths.
*
* @since 2.4
*/
@Parameter( property = "maven.resources.escapeWindowsPaths", defaultValue = "true" )
protected boolean escapeWindowsPaths;
/**
*
* Set of delimiters for expressions to filter within the resources. These delimiters are specified in the
* form 'beginToken*endToken'. If no '*' is given, the delimiter is assumed to be the same for start and end.
*
* So, the default filtering delimiters might be specified as:
*
*
*
* ${*}
* @
*
*
*
* Since the '@' delimiter is the same on both ends, we don't need to specify '@*@' (though we can).
*
*
* @since 2.4
*/
@Parameter
protected List delimiters;
/**
* @since 2.4
*/
@Parameter( defaultValue = "true" )
protected boolean useDefaultDelimiters;
/**
*
* List of plexus components hint which implements {@link MavenResourcesFiltering#filterResources(MavenResourcesExecution)}.
* They will be executed after the resources copying/filtering.
*
*
* @since 2.4
*/
@Parameter
private List mavenFilteringHints;
/**
* @since 2.4
*/
private PlexusContainer plexusContainer;
/**
* @since 2.4
*/
private List mavenFilteringComponents = new ArrayList();
/**
* stop searching endToken at the end of line
*
* @since 2.5
*/
@Parameter( property = "maven.resources.supportMultiLineFiltering", defaultValue = "false" )
private boolean supportMultiLineFiltering;
public void contextualize( Context context )
throws ContextException
{
plexusContainer = (PlexusContainer) context.get( PlexusConstants.PLEXUS_KEY );
}
public void execute()
throws MojoExecutionException
{
try
{
if ( StringUtils.isEmpty( encoding ) && isFilteringEnabled( getResources() ) )
{
getLog().warn( "File encoding has not been set, using platform encoding " + ReaderFactory.FILE_ENCODING
+ ", i.e. build is platform dependent!" );
}
//获取资源文件过滤器配置
List filters = getCombinedFiltersList();
//根据现有配置信息创建Resources处理器对象实例
MavenResourcesExecution mavenResourcesExecution =
new MavenResourcesExecution( getResources(), getOutputDirectory(), project, encoding, filters,
Collections.emptyList(), session );
//windows路径处理
mavenResourcesExecution.setEscapeWindowsPaths( escapeWindowsPaths );
// never include project build filters in this call, since we've already accounted for the POM build filters
// above, in getCombinedFiltersList().
mavenResourcesExecution.setInjectProjectBuildFilters( false );
mavenResourcesExecution.setEscapeString( escapeString );
mavenResourcesExecution.setOverwrite( overwrite );
mavenResourcesExecution.setIncludeEmptyDirs( includeEmptyDirs );
mavenResourcesExecution.setSupportMultiLineFiltering( supportMultiLineFiltering );
// if these are NOT set, just use the defaults, which are '${*}' and '@'.
if ( delimiters != null && !delimiters.isEmpty() )
{
LinkedHashSet delims = new LinkedHashSet();
if ( useDefaultDelimiters )
{
delims.addAll( mavenResourcesExecution.getDelimiters() );
}
for ( String delim : delimiters )
{
if ( delim == null )
{
// FIXME: ${filter:*} could also trigger this condition. Need a better long-term solution.
delims.add( "${*}" );
}
else
{
delims.add( delim );
}
}
mavenResourcesExecution.setDelimiters( delims );
}
if ( nonFilteredFileExtensions != null )
{
mavenResourcesExecution.setNonFilteredFileExtensions( nonFilteredFileExtensions );
}
mavenResourcesFiltering.filterResources( mavenResourcesExecution );
//执行Resource文件拷贝
executeUserFilterComponents( mavenResourcesExecution );
}
catch ( MavenFilteringException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
}
/**
* @since 2.5
*/
protected void executeUserFilterComponents( MavenResourcesExecution mavenResourcesExecution )
throws MojoExecutionException, MavenFilteringException
{
if ( mavenFilteringHints != null )
{
for ( Iterator ite = mavenFilteringHints.iterator(); ite.hasNext(); )
{
String hint = (String) ite.next();
try
{
mavenFilteringComponents.add(
(MavenResourcesFiltering) plexusContainer.lookup( MavenResourcesFiltering.class.getName(),
hint ) );
}
catch ( ComponentLookupException e )
{
throw new MojoExecutionException( e.getMessage(), e );
}
}
}
else
{
getLog().debug( "no use filter components" );
}
if ( mavenFilteringComponents != null && !mavenFilteringComponents.isEmpty() )
{
getLog().debug( "execute user filters" );
for ( MavenResourcesFiltering filter : mavenFilteringComponents )
{
filter.filterResources( mavenResourcesExecution );
}
}
}
protected List getCombinedFiltersList()
{
if ( filters == null || filters.isEmpty() )
{
return useBuildFilters ? buildFilters : null;
}
else
{
List result = new ArrayList();
if ( useBuildFilters && buildFilters != null && !buildFilters.isEmpty() )
{
result.addAll( buildFilters );
}
result.addAll( filters );
return result;
}
}
/**
* Determines whether filtering has been enabled for any resource.
*
* @param resources The set of resources to check for filtering, may be
null
.
* @return
true
if at least one resource uses filtering,
false
otherwise.
*/
private boolean isFilteringEnabled( Collection resources )
{
if ( resources != null )
{
for ( Resource resource : resources )
{
if ( resource.isFiltering() )
{
return true;
}
}
}
return false;
}
}
上面只是介绍了Maven生命周期阶段绑定执行代码的基本模式,由于maven的生命周期众多,并且每个生命周期内有可能绑定多个Mojo,如果使用上述的模式简单关联的话,会显得结构组织很乱。
maven会根据Mojo功能的划分,将具有相似功能的Mojo放到一个插件中。并且某一个特定的Mojo能实现的功能称为 goal,即目标,表明该Mojo能实现什么目标。
##四、绑定
创建项目的源码包, maven-source-plugin插件的jar-no-fork目标能够将项目的主代码打包成jar文件, 可以将其绑定到verify阶段上:
org.apache.maven.plugins
maven-source-plugin
3.0.0
attach-sources
verify
jar-no-fork