Maven插件开发过程中的一些坑

code

Maven插件开发过程中的一些坑

背景

去年底写了一个 maven 插件,类似功能大概是解析 @Controller 以及其他的注解,生成一份类似接口文档的东西,标明出入参啥的,用 maven 插件可以尽量少的侵入代码,一开始是使用的一个文本解析库Qdox,但是经过验证有些功能不满足我们的需求,想了下 Maven 反正是在在构建时执行的,可以直接想办法获取 Classloader 然后用反射来获取需要的属性,在这个过程中踩了一些坑。记录一下这些坑。

maven插件在root工程执行,不在每个模块工程都执行一次

一开始发现这个maven插件在所有的模块都会跑一次,我本来在root工程执行的时候就回去收集所有信息了,不需要跑多次

解决方案,在@Mojo注解中 添加上 aggregator=true

aggregator

maven插件在编译后在执行

因为要用反射嘛,所以一定要编译完之后才能用

最靠谱的方案是把你的 Maven 插件配置好对应的声明周期,配置在 compile 或者 prepare_package 之后就行了。当然你的用户可能 xjb 改你的执行周期,所以这个问题也可以等价为

maven插件在执行前先单独执行生命周期

在入口Mojo处加上@Execute注解,里面可以填写需要的生命周期

参考官方文档

execute.png

获取目标工程所有依赖信息

首先需要在 @Mojo 注解上加上 requiresDependencyResolution 配置,这个配置表明需要在执行前解析指定类路径中的依赖关系,参考官方文档,

requiresDependencyResolution

还有一个类似的配置 requiresDependencyCollectionrequiresDependencyResolution 类似,支持相同的值。区别在于,该配置不会解析依赖关系的文件,即与Maven项目相关的依赖可以缺少一个文件。因此,该注释适用于那些只想分析依赖关系的 mojo,尤其是在生命周期的早期阶段,由于项目尚未建立,完全的依赖关系解析可能会失败。

配置了这个之后就能通过 Maven-CoreMavenProject 类获取所有的依赖

获取目标工程的 ClassLoader

再配置了解析依赖信息之后,参考

Access project classes from a maven plugin

这样自定义一个classloader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
private ClassLoader getClassLoader(MavenProject project)
{
try
{
List classpathElements = project.getCompileClasspathElements();
classpathElements.add( project.getBuild().getOutputDirectory() );
classpathElements.add( project.getBuild().getTestOutputDirectory() );
URL urls[] = new URL[classpathElements.size()];
for ( int i = 0; i < classpathElements.size(); ++i )
{
urls[i] = new File( (String) classpathElements.get( i ) ).toURL();
}
return new URLClassLoader( urls, this.getClass().getClassLoader() );
}
catch ( Exception e )
{
getLog().debug( "Couldn't get the classloader." );
return this.getClass().getClassLoader();
}
}

参考

Maven – Mojo API Specification

Maven – Introduction to the Build Lifecycle

Access project classes from a maven plugin

Load project class within maven mojo

本文作者:Keshane

本文链接: https://keshane.moe/2023/03/30/maven-plugin-development-tips/

评论

您所在的地区可能无法访问 Disqus 评论系统,请切换网络环境再尝试。