当一家公司上了一定的规模,项目越来越多,代码也越来越庞大,然后就是各种五花八门的代码格式、代码规范,通过主程们code review 耗时耗力,很多主程也缺少主观能动性和精力去cover code review这事项,如果有东西能自动化去检查团队成员的编码规范,这样就可以大大的提高代码质量,也可以让核心人员从code review 中解脱出来,本文提到的P3C-PMD就是这种神器。
p3c-pmd是静态代码自动扫描框架,规则是基于pmd规则上修改而来,可以直接参考pmd与jekins集成文档,将规则包换成p3c的包就可以,集成在sonar或gradle或jekins及在线扫描,在流水线上做个定时任务,每天定时扫描,同时它也支持自定义规则,让团队根据自身的需求。
类似的神器还有腾讯的codecc等。
P3C的git仓库如下:
https://github.com/alibaba/p3c/
下面简单说说使用:
1.使用三种方式
1.1. Eclipse plugin
1.2. IDEA plugin
1.3. 命令行扫描
2 规范
规范符合阿里 JAVA代码规范,大的54种大的规则和一系列的小规则,请参考:Java开发手册(黄山版).pdf
3.如何自定义规则
1.如何新增规范(命令行):
如何提示System.currentTimeMillis()
的禁用?
Summary
Rule name | Number of violations |
AvoidCallSystemCurrentTimeMillisRule | 1 |
PMD report
Problems found
File | Line | Problem |
java/com/yorha/game/controller/UserController.java | 45 |
核心类:AvoidCallSystemCurrentTimeMillisRule.java
/** * don't Use System.currentTimeMillis() to get the current millisecond. user SystemClock.now(). * * * @author Allen Jiang */ public class AvoidCallSystemCurrentTimeMillisRule extends AbstractXpathRule { private static final String XPATH = "//PrimaryPrefix/Name[@Image='System.currentTimeMillis']"; public AvoidCallSystemCurrentTimeMillisRule() { setXPath(XPATH); } @Override public void addViolation(Object data, Node node, String arg) { ViolationUtils.addViolationWithPrecisePosition(this, node, data, I18nResources.getMessage("java.extend.AvoidCallSystemCurrentTimeMillisRule.violation.msg")); } }
国际化
messages.xml
<entry key="java.extend.AvoidCallSystemCurrentTimeMillisRule.rule.msg"> <![CDATA[获取当前毫秒数:SystemClock.now(); 而不是System.currentTimeMillis();]]> </entry> <entry key="java.extend.AvoidCallSystemCurrentTimeMillisRule.rule.desc"> <![CDATA[ 说明:如果想获取更加精确的纳秒级时间值,用SystemClock.nanoTime。在JDK8中,针对统计时间等场景,推荐使用Instant类。 ]]> </entry> <entry key="java.extend.AvoidCallSystemCurrentTimeMillisRule.violation.msg"> <![CDATA[请使用SystemClock.now()代替System.currentTimeMillis()]]> </entry>
messages_en.xml
<entry key="java.extend.AvoidCallSystemCurrentTimeMillisRule.rule.msg"> <![CDATA[Use SystemClock.now() to get the current millisecond. Do not use System.currentTimeMillis(). ]]> </entry> <entry key="java.extend.AvoidCallSystemCurrentTimeMillisRule.rule.desc"> <![CDATA[ Note: In order to get a more accurate time, use SystemClock.nanoTime(). In JDK8, use Instant class to deal with situations like time statistics. ]]> </entry> <entry key="java.extend.AvoidCallSystemCurrentTimeMillisRule.violation.msg"> <![CDATA[please use SystemClock.now() instead of System.currentTimeMillis()]]> </entry>
rulesets/ali-extend.xml
<?xml version="1.0"?> <ruleset name="AlibabaJavaExtends" xmlns="http://pmd.sourceforge.net/ruleset/2.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd"> <description>AlibabaJavaExtends</description> <rule name="AvoidCallSystemCurrentTimeMillisRule" language="java" message="java.extend.AvoidCallSystemCurrentTimeMillisRule.rule.msg" class="com.alibaba.p3c.pmd.lang.java.rule.extend.AvoidCallSystemCurrentTimeMillisRule"> <description>java.extend.AvoidCallSystemCurrentTimeMillisRule.rule.desc</description> <priority>1</priority> <example> <![CDATA[ public class TimeMillisDemo { public static void main(String args[]) { // Positive example: long a = SystemClock.now(); // Negative example: long b = System.currentTimeMillis(); System.out.println(a); System.out.println(b); } } ]]> </example> </rule> </ruleset>
4.如何屏蔽规范:
在命令行中,可以根据优先级屏蔽部分规则,根据你需要的加入ruleset白名单黑名单规则
5.如何启动
java -server -jar $PWD/p3c-pmd-2.1.1.jar -d ../../../proj/yorha-game/src/main -f summaryhtml -cache cache.log -shortnames -R rulesets/java/ali-exception.xml,rulesets/java/ali-oop.xml,rulesets/java/ali-flowcontrol.xml,rulesets/java/ali-naming.xml,rulesets/java/ali-extend.xml -r /home/cnc_build/pmd/report.html -encoding UTF-8 > p3c.log 2>&1 &
具体使用选项说明如下:
Usage: pmd [options] Options: -failOnViolation, --failOnViolation By default PMD exits with status 4 if violations are found. Disable this option with '-failOnViolation false' to exit with 0 instead and just write the report. Default: true -auxclasspath Specifies the classpath for libraries used by the source code. This is used by the type resolution. Alternatively, a 'file://' URL to a text file containing path elements on consecutive lines can be specified. -benchmark, -b Benchmark mode - output a benchmark report upon completion; default to System.err. Default: false -cache Specify the location of the cache file for incremental analysis. This should be the full path to the file, including the desired file name (not just the parent directory). If the file doesnt exist, it will be created on the first run. The file will be overwritten on each run with the most up-to-date rule violations. -dir, -d Root directory for sources. -encoding, -e Specifies the character set encoding of the source code files PMD is reading (i.e., UTF-8). Default: UTF-8 -filelist Path to a file containing a list of files to analyze. -format, -f Report format type. Default: text -help, -h, -H Display help on usage. -ignorelist Path to a file containing a list of files to ignore. -language, -l Specify a language PMD should use. -minimumpriority, -min Rule priority threshold; rules with lower priority than configured here won.t be used. Valid values are integers between 1 and 5 (inclusive), with 5 being the lowest priority. Default: 5 -no-cache Explicitly disable incremental analysis. The '-cache' option is ignored if this switch is present in the command line. Default: false -norulesetcompatibility Disable the ruleset compatibility filter. The filter is active by default and tries automatically 'fix' old ruleset files with old rule names Default: false -property, -P {name}={value}: Define a property for the report format. Default: [] -reportfile, -r Sends report output to a file; default to System.out. * -rulesets, -R Comma separated list of ruleset names to use. -shortnames Prints shortened filenames in the report. Default: false -showsuppressed Report should show suppressed rule violations. Default: false -stress, -S Performs a stress test. Default: false -suppressmarker Specifies the string that marks a line which PMD should ignore; default is NOPMD. Default: NOPMD -threads, -t Sets the number of threads used by PMD. Default: 1 -uri, -u Database URI for sources. -debug, -verbose, -D, -V Debug mode. Default: false -version, -v Specify version of a language PMD should use.
5.静态扫描流水线
拉取最新代码—>每日定时扫描—>生成报表—>发送链接到企业微信群
Summary
Rule name | Number of violations |
AbstractClassShouldStartWithAbstractNamingRule | 20 |
ClassNamingShouldBeCamelRule | 11 |
AvoidComplexConditionRule | 7 |
AvoidStartWithDollarAndUnderLineNamingRule | 1 |
PojoMustOverrideToStringRule | 1 |
SwitchStatementRule | 2 |
LowerCamelCaseVariableNamingRule | 64 |
EqualsAvoidNullRule | 3 |
AvoidCallSystemCurrentTimeMillisRule | 1 |
ConstantFieldShouldBeUpperCaseRule | 13 |
PackageNamingRule | 67 |
PojoMustUsePrimitiveFieldRule | 6 |
# | File | Line | Problem |
1 | java/com/yorha/game/controller/IOController.java | 19 | 【IOController】不符合UpperCamelCase命名风格 |
2 | java/com/yorha/game/controller/UserController.java | 45 | 请使用SystemClock.now()代替System.currentTimeMillis() |
3 | java/com/yorha/game/db/GameTcaplusManager.java | 253 | 变量名【ScenePlayerId】不符合lowerCamelCase命名风格 |
4 | java/com/yorha/game/db/GameTcaplusManager.java | 410 | 变量名【ClanId】不符合lowerCamelCase命名风格 |
5 | java/com/yorha/game/db/GameTcaplusManager.java | 424 | 变量名【ClanId】不符合lowerCamelCase命名风格 |
6 | java/com/yorha/game/db/GameTcaplusManager.java | 459 | 变量名【ClanId】不符合lowerCamelCase命名风格 |
7 | java/com/yorha/game/db/GameTcaplusManager.java | 489 | 方法名【getPlayerEntityDBX】不符合lowerCamelCase命名风格 |
P3C和CodeCC的比较
名称 | P3C | CodeCC |
便利性 | 需要自行打包,配置规则和命令行 | 很方便,直接界面操作使用 |
界面友好性 | 只有明细,没有界面 | 能看到综合信息 |
默认扫描规则 | 默认54条规则 | 默认51条针对JAVA的规则,如要其他规则,还可以从627条备用规则里去选 |
自定义规则 | 支持扩展 ,但要学习XPATH 的语法 |
当前版本暂不支持「自定义规则的添加」,相关功能在排期开发中 |
蓝盾流水线整合 | 很方便 | 通过添加插件的方式,不支持私有构建机,可使用Docker公共构建机执行插件 |
报表明细 | 只能看到某一行出现了代码问题,但不能定位到责任人是谁 | 能定位到问题,责任人,以及代码质量的发展和修复趋势,还可以跟进问题的状态及评论 |
过滤规则 | 通过去掉rule配置 | 通过页面勾选 |
总结
总之,项目越来越大,团队越来越大,代码越来越来多,然后就是各种五花八门的代码格式、代码规范。通过阿里P3C-PMD配合Gitlab做编码规范检查,可以大大提升团队代码质量。