为了便于大家实践,下面将详细演示如何实际编写一个简单的用于代码行统计的Maven插件。使用该插件,用户可以了解到Maven项目中各个源代码目录下文件的数量,以及它们加起来共有多少代码行。不过,笔者强烈反对使用代码行来考核程序员,因为大家都知道,代码的数量并不能真正反映一个程序员的价值。
要创建一个Maven插件项目,首先使用maven-archetype-plugin命令:
然后选择:
输入Maven坐标等信息之后,一个Maven插件项目就创建好了。打开项目的pom.xml可以看到如代码清单17-1所示的内容。
代码清单17-1 代码行统计插件的POM
Maven插件项目的POM有两个特殊的地方:
1)它的packaging必须为maven-plugin,这种特殊的打包类型能控制Maven为其在生命周期阶段绑定插件处理相关的目标,例如在compile阶段,Maven需要为插件项目构建一个特殊插件描述符文件。
2)从上述代码中可以看到一个artifactId为maven-plugin-api的依赖,该依赖中包含了插件开发所必需的类,例如稍后会看到的AbstractMojo。需要注意的是,代码清单17-1中并没有使用默认Archetype生成的maven-plugin-api版本,而是升级到了3.0,这样做的目的是与Maven的版本保持一致。
插件项目创建好之后,下一步是为插件编写目标。使用Archetype生成的插件项目包含了一个名为MyMojo的Java文件,我们将其删除,然后自己创建一个CountMojo,如代码清单17-2所示。
代码清单17-2 CountMojo的主要代码
首先,每个插件目标类,或者说Mojo,都必须继承AbstractMojo并实现execute()方法,只有这样Maven才能识别该插件目标,并执行execute()方法中的行为。其次,由于历史原因,上述CountMojo类使用了Java 1.4风格的标注(将标注写在注释中),这里要关注的是@goal,任何一个Mojo都必须使用该标注写明自己的目标名称,有了目标定义之后,我们才能在项目中配置该插件目标,或者在命令行调用之。例如:
创建一个Mojo所必要的工作就是这三项:继承AbstractMojo、实现execute()方法、提供@goal标注。
下一步是为插件提供配置点。我们希望该插件默认统计所有Java、XML,以及properties文件,但是允许用户配置包含哪些类型的文件。代码清单17-2中的includes字段就是用来为用户提供该配置点的,它的类型为String数组,并且使用了@parameter参数表示用户可以在使用该插件的时候在POM中配置该字段,如代码清单17-3所示。
代码清单17-3 配置CountMojo的includes参数
代码清单17-3配置了CountMojo统计Java和SQL文件,而不是默认的Java、XML和Properties。
代码清单17-2中还包含了basedir、sourceDirectory、testSourceDirectory等字段,它们都使用了@parameter标注,但同时关键字expression表示从系统属性读取这几个字段的值。${project.basedir}、${project.build.sourceDirectory}、${project.build.testSourceDirectory}等表达式读者应该已经熟悉,它们分别表示了项目的基础目录、主代码目录和测试代码目录。@readonly标注表示不允许用户对其进行配置,因为对于一个项目来说,这几个目录位置都是固定的。
了解这些简单的配置点之后,下一步就该实现插件的具体行为了。从代码清单17-2的execute()方法中大家能看到这样一些信息:如果用户没有配置includes则就是用默认的统计包含配置,然后再分别统计项目主代码目录、测试代码目录、主资源目录,以及测试资源目录。这里涉及一个countDir()方法,其具体实现如代码清单17-4所示。
代码清单17-4 CountMojo的具体行为实现
这里简单解释一下上述三个方法:collectFiles()方法用来递归地收集一个目录下所有应当被统计的文件,countLine()方法用来统计单个文件的行数,而countDir()则借助上述两个方法统计某一目录下共有多少文件被统计,以及这些文件共包含了多少代码行。
代码清单17-2中的execute()方法包含了简单的异常处理,代码行统计的时候由于涉及了文件操作,因此可能会抛出IOException。当捕获到IOException的时候,使用MojoExecutationException对其简单包装后再抛出,Maven执行插件目标的时候如果遇到MojoExecutationException,就会在命令行显示“BUILD ERROR”信息。
代码清单17-4中的countDir()方法的最后一行使用了AbstractMojo的getLog()方法,该方法返回一个类似于Log4j的日志对象,可以用来将输出日志到Maven命令行。这里使用了info级别的日志告诉用户某个路径下有多少文件被统计,共包含了多少代码行,因此在使用该插件的时候可以看到如下的Maven输出:
使用mvn clean install命令将该插件项目构建并安装到本地仓库后,就能使用它统计Maven项目的代码行了。如下所示:
如果嫌命令行太长太复杂,可以将该插件的groupId添加到settings.xml中。如下所示:
现在Maven命令行就可以简化成:
这里面的具体原理可参考7.8.4节。