欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

maven 自定义插件小示例

程序员文章站 2022-04-30 18:12:54
...
maven作为一个核心是插件的架构,所有的工作都通过插件来执行,主要分为两类build和report
  • Build plugins:在build阶段执行,在pom中必须配置在<build/>标签里面
  • Reporting plugins:在生成site阶段执行,在pom中配置在<reporting/>标签里面。

maven官方已经给我们提供了各种各样的插件maven plugins,但有时我们还是需要自己定义我们特殊的插件,比如我们项目中根据特定的文件,自动生成对应的java类,这时就需要我们实现自己的特定插件了,本示例包含两个工程,
  • 插件工程:maven-plugin-test
  • 使用插件的工程:maven-plugin-client-test

为了使示例保持简单,插件工程只演示了从特定目录下读取特定文件类型,并没有生成java类。

1.插件工程
1.1 工程结构

maven 自定义插件小示例
            
    
    博客分类: maven mavenplugin 

1.2 Mojo类
/**
 * 
 */
package falcon.chengf.maven.plugin.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.Map;

import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.project.MavenProject;
import org.apache.maven.shared.model.fileset.FileSet;
import org.apache.maven.shared.model.fileset.util.FileSetManager;
import org.yaml.snakeyaml.Yaml;

/**
 * read content from yaml files (.yml)
 *
 * @goal readyml
 * @phase generate-sources
 * @threadSafe
 */
public class ReadYmlMojo extends AbstractMojo {

	/**
	 * The source directory of yml files. This directory is added to the
	 * classpath at schema compiling time. All files can therefore be referenced
	 * as classpath resources following the directory structure under the source
	 * directory.
	 *
	 * @parameter property="sourceDirectory"
	 *            default-value="${basedir}/src/main/resources"
	 */
	private File sourceDirectory;

	/**
	 * @parameter property="outputDirectory"
	 *            default-value="${project.build.directory}/generated-sources/yml"
	 */
	private File outputDirectory;

	/**
	 * @parameter property="sourceDirectory"
	 *            default-value="${basedir}/src/test/resources"
	 */
	private File testSourceDirectory;

	/**
	 * @parameter property="outputDirectory"
	 *            default-value="${project.build.directory}/generated-test-sources/yml"
	 */
	private File testOutputDirectory;

	/**
	 * A set of Ant-like inclusion patterns used to select files from the source
	 * directory for processing. By default, the pattern
	 * <code>**&#47;*.yml</code> is used to select grammar files.
	 * 
	 * @parameter property="includes"
	 **/

	private String[] includes = new String[] { "**/*.yml" };

	/**
	 * A set of Ant-like inclusion patterns used to select files from the source
	 * directory for processing. By default, the pattern
	 * <code>**&#47;*.yml</code> is used to select grammar files.
	 *
	 * @parameter
	 */
	private String[] testIncludes = new String[] { "**/*.yml" };

	/**
	 * A set of Ant-like exclusion patterns used to prevent certain files from
	 * being processed. By default, this set is empty such that no files are
	 * excluded.
	 *
	 * @parameter
	 */
	protected String[] excludes = new String[0];

	/**
	 * A set of Ant-like exclusion patterns used to prevent certain files from
	 * being processed. By default, this set is empty such that no files are
	 * excluded.
	 *
	 * @parameter
	 */
	protected String[] testExcludes = new String[0];

	/**
	 * The current Maven project.
	 *
	 * @parameter default-value="${project}"
	 * @readonly
	 * @required
	 */
	protected MavenProject project;

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.apache.maven.plugin.Mojo#execute()
	 */
	public void execute() throws MojoExecutionException, MojoFailureException {
		getLog().info("start to read content from yml file");
		getLog().info("sourceDirectory:" + sourceDirectory.getAbsolutePath());
		getLog().info("outputDirectory:" + outputDirectory.getAbsolutePath());
		getLog().info("includes:" + Arrays.asList(includes));
		boolean hasSourceDir = null != sourceDirectory && sourceDirectory.isDirectory();
		boolean hasTestDir = null != testSourceDirectory && testSourceDirectory.isDirectory();
		if (!hasSourceDir && !hasTestDir) {
			throw new MojoExecutionException("neither sourceDirectory: " + sourceDirectory + " or testSourceDirectory: "
					+ testSourceDirectory + " are directories");
		}
		if (hasSourceDir) {
			String[] includedFiles = getIncludedFiles(sourceDirectory.getAbsolutePath(), excludes, getIncludes());
			readFiles(includedFiles, sourceDirectory, outputDirectory);
		}

		if (hasTestDir) {
			String[] includedFiles = getIncludedFiles(testSourceDirectory.getAbsolutePath(), testExcludes,
					getTestIncludes());
			readFiles(includedFiles, testSourceDirectory, testOutputDirectory);
			project.addTestCompileSourceRoot(testOutputDirectory.getAbsolutePath());
		}
		
		
		getLog().info("read from yml file end");
	}

	/**
	 * 根据条件过滤需要处理的文件
	 * @param absPath
	 * @param excludes
	 * @param includes
	 * @return
	 */
	private String[] getIncludedFiles(String absPath, String[] excludes, String[] includes) {
		FileSetManager fileSetManager = new FileSetManager();
		FileSet fs = new FileSet();
		fs.setDirectory(absPath);
		fs.setFollowSymlinks(false);

		for (String include : includes) {
			fs.addInclude(include);
		}
		for (String exclude : excludes) {
			fs.addExclude(exclude);
		}
		return fileSetManager.getIncludedFiles(fs);
	}

	private void readFiles(String[] files, File sourceDir, File outDir) throws MojoExecutionException {
		for (String filename : files) {
			getLog().info("read content from file " + filename);
			try {
				doRead(filename, sourceDir, outDir);
			} catch (IOException e) {
				throw new MojoExecutionException("Error compiling protocol file " + filename + " to " + outDir, e);
			}
		}
	}

	private static final Yaml yaml = new Yaml();

	protected void doRead(String filename, File sourceDirectory, File outputDirectory) throws IOException {
		File src = new File(sourceDirectory, filename);

		// 通过snakeyml读取yml文件内容
		Map<String,Object> content= (Map)yaml.load(new FileInputStream(src));
		getLog().info(filename+"'s content is"+content.toString());
	}


	protected String[] getIncludes() {
		return includes;
	}

	protected String[] getTestIncludes() {
		return testIncludes;
	}
}



注意点
  • 1.ReadYmlMojo类上面的注释中有三个注解,这三个注解有特定含义,不能省略,其中@goal 对应的值(readyml)必须和pom.xml中的goal一致
  • 2.属性上面注释中的@parameter注解也有特殊含义,不能省略,如sourceDirectory上的@parameter property="sourceDirectory"要和使用插件工程的pom中指定的参数一致

1.3 插件工程的pom文件
<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>falcon.chengf</groupId>
	<artifactId>maven-plugin-test</artifactId>
	<version>1.0</version>

	<packaging>maven-plugin</packaging>

	<name>maven-plugin-test</name>
	<url>http://maven.apache.org</url>
	
	<properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.version>2.0.10</maven.version>
        <file-management.version>1.2.1</file-management.version>
    </properties>
    
    <dependencies>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-plugin-api</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>org.yaml</groupId>
            <artifactId>snakeyaml</artifactId>
            <version>1.10</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven</groupId>
            <artifactId>maven-project</artifactId>
            <version>${maven.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.shared</groupId>
            <artifactId>file-management</artifactId>
            <version>${file-management.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.maven.plugin-tools</groupId>
            <artifactId>maven-plugin-annotations</artifactId>
            <version>3.2</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>org.codehaus.plexus</groupId>
            <artifactId>plexus-utils</artifactId>
            <version>3.0.8</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-plugin-plugin</artifactId>
                <version>3.2</version>
                <configuration>
                    <goalPrefix>readyml</goalPrefix>
                    <skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
                </configuration>
                <executions>
                    <execution>
                        <id>mojo-descriptor</id>
                        <goals>
                            <goal>descriptor</goal>
                        </goals>
                    </execution>
                    <execution>
                        <id>help-goal</id>
                        <goals>
                            <goal>helpmojo</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <profile>
            <id>jdk-1.8</id>
            <activation>
                <activeByDefault>true</activeByDefault>
                <jdk>1.8</jdk>
            </activation>
            <properties>
                <maven.compiler.source>1.8</maven.compiler.source>
                <maven.compiler.target>1.8</maven.compiler.target>
                <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
            </properties>
        </profile>
    </profiles>
</project>


可以看到 goalPrefix 对应的属性值和mojojava类中的值时一样的

2 使用插件的工程
2.1 工程结构

maven 自定义插件小示例
            
    
    博客分类: maven mavenplugin 
2.2 pom文件
<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/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>falcon.chengf</groupId>
	<artifactId>maven-plugin-client-test</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<name>maven-plugin-client-test</name>
	<url>http://maven.apache.org</url>
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>

	</dependencies>

	<build>
		<sourceDirectory>${project.basedir}/target/generated-sources</sourceDirectory>
		<plugins>
			<plugin>
				<groupId>falcon.chengf</groupId>
				<artifactId>maven-plugin-test</artifactId>
				<version>1.0</version>
				<configuration>
					<skipErrorNoDescriptorsFound>true</skipErrorNoDescriptorsFound>
				</configuration>
				<executions>
					<execution>
						<id>readyml</id>
						<phase>generate-sources</phase>
						<goals>
							<goal>readyml</goal>
						</goals>
						<configuration>
							<sourceDirectory>${project.basedir}/src/main/resources/yml</sourceDirectory>
							<outputDirectory>${project.basedir}/target/generated-sources</outputDirectory>
							<includes>
								<include>**/*.yml</include>
							</includes>
						</configuration>
					</execution>
				</executions>
			</plugin>
		</plugins>
		<pluginManagement>
			<plugins>
				<!--This plugin's configuration is used to store Eclipse m2e settings 
					only. It has no influence on the Maven build itself. -->
				<plugin>
					<groupId>org.eclipse.m2e</groupId>
					<artifactId>lifecycle-mapping</artifactId>
					<version>1.0.0</version>
					<configuration>
						<lifecycleMappingMetadata>
							<pluginExecutions>
								<pluginExecution>
									<pluginExecutionFilter>
										<groupId>falcon.chengf</groupId>
										<artifactId>
											maven-plugin-test
										</artifactId>
										<versionRange>
											[0.0.1-SNAPSHOT,)
										</versionRange>
										<goals>
											<goal>readyml</goal>
										</goals>
									</pluginExecutionFilter>
									<action>
										<ignore></ignore>
									</action>
								</pluginExecution>
							</pluginExecutions>
						</lifecycleMappingMetadata>
					</configuration>
				</plugin>
			</plugins>
		</pluginManagement>
	</build>
</project>



注意点:
  • execution中的id属性要和插件工程对应的goal一致
  • configuration中的属性如outputDirectory要和插件工程中@parameter的property值一致
  • 在eclipse中引用插件工程后回报如下错误

  • maven 自定义插件小示例
            
    
    博客分类: maven mavenplugin 

    直接选择第二项忽略即可


在使用插件的工程中创建/src/main/resources/yml文件,存入test.yml内容如下:
name: chengf
level: 11


执行maven package命令,可以在控制台看到maven插件正确执行,解析的test.yml文件的内容
maven 自定义插件小示例
            
    
    博客分类: maven mavenplugin 

完整工程代码请参考附件
  • maven 自定义插件小示例
            
    
    博客分类: maven mavenplugin 
  • 大小: 124 KB
  • maven 自定义插件小示例
            
    
    博客分类: maven mavenplugin 
  • 大小: 52.7 KB
  • maven 自定义插件小示例
            
    
    博客分类: maven mavenplugin 
  • 大小: 29.8 KB
  • maven 自定义插件小示例
            
    
    博客分类: maven mavenplugin 
  • 大小: 41.1 KB
相关标签: maven plugin