代碼不只是用來運行的,更是用來閱讀的
編碼規(guī)范
代碼規(guī)范看似只是簡單的一個編碼的規(guī)范,對代碼格式、變量命名、注釋格式等做一個統(tǒng)一規(guī)范,看似有點強迫你改變編碼風格的味道。但是當你和許多團隊協(xié)同開發(fā)過許多項目,寫過許多代碼之后再回頭來看的話,你就會發(fā)現(xiàn)它真的就是個規(guī)范,啊不,真的是個好東西。有沒有看過國慶閱兵上的方陣,當所有軍人著裝統(tǒng)一,排列整齊,一起從長安街走過得時候,會不會被他們帶來的視覺沖擊所震撼。編碼規(guī)范就如其中的軍規(guī),當大量的代碼都具有統(tǒng)一性整齊性時,帶給每個參與的人的視覺效果也是極具沖擊性的。當然除了視覺效果,愉悅了心情之外,這種統(tǒng)一性,為每個參與編碼的人員統(tǒng)一了風格,彼此之間互相閱讀代碼的效率就高了,團隊間的協(xié)作效率也就高了。常見的比較受認可的編碼規(guī)范,基本都是大廠的(廢話,沒點頭銜在高傲的程序猿前誰會服誰),例如:Google、Sun、阿里巴巴等大廠都有發(fā)布自己的編碼規(guī)范,這些可都是集萬千大神的工程實踐總結,這些總結幫助行業(yè)人員提高了開發(fā)質量和效率,大大降低了代碼的維護成本。
阿里巴巴JAVA編碼規(guī)范
好多大廠都發(fā)布了編碼規(guī)范,為何選阿里巴巴的呢?第一,阿里給的規(guī)范更加符合國人的習慣,畢竟里面絕大部分都是國人;第二就是阿里的規(guī)范文檔都是中文的,方便閱讀,也降低了一些翻譯的歧義性等等。(真實理由其實就一個,我英文不好)有用過谷歌規(guī)范的再去用阿里的就會深有體會了,谷歌的規(guī)范畢竟比較符合西方人習慣,很多注釋上的規(guī)范很蛋疼的。
阿里巴巴的JAVA編程規(guī)范,至今為止已更迭了多個版本,2018年6月6日,《阿里巴巴Java開發(fā)手冊(詳盡版)》v1.4正式在GitHub上發(fā)布,這是史上內容最全、修正最為徹底的一個版本,并且增加了單元測試規(guī)約內容,這也是阿里官方對外發(fā)布的最后一個PDF版本,值得收藏。
《阿里巴巴Java開發(fā)手冊》是阿里內部Java工程師所遵循的開發(fā)規(guī)范,涵蓋編程規(guī)約、單元測試規(guī)約、異常日志規(guī)約、MySQL規(guī)約、工程規(guī)約、安全規(guī)約等,這是近萬名阿里Java技術精英的經驗總結,并經歷了多次大規(guī)模一線實戰(zhàn)檢驗及完善。這是阿里回饋給Java社區(qū)的一份禮物,希望能夠幫助企業(yè)開發(fā)團隊在Java開發(fā)上更高效、容錯、有協(xié)作性,提高代碼質量,降低項目維護成本。
這里是阿里巴巴Java編碼規(guī)范的GitHub傳送門。里面提供了多種代碼規(guī)范檢測方式:
- IntelliJ IDEA插件集成方式
- Eclipse 插件集成方式
- pmd工具集成方式
對應的IDE插件可以看一下這篇文章《阿里巴巴Java開發(fā)規(guī)約插件p3c詳細教程及使用感受》
為了和GitLab能夠配合,進行提交時自動化得代碼檢查,這邊選擇了第三種pmd工具集成方式。
打成PMD工具Jar包
由于阿里的GitHub中p3c/p3c-pmd提供的只是規(guī)則代碼,主體PMD代碼是以依賴方式引入,要把它制作成一個可獨立運行的工具包,需要將所有依賴的包都封裝到一起,打成一個胖Jar包,才能夠在本地獨立得運行。
- 從GitHub中把p3c的代碼庫下載下來(可用git clone也可以直接在GitHub中下載zip包)
- 安裝Gradle
- 進入到p3c-pmd目錄中,初始化Gradle項目
# gradle init
- 編輯build.gradle,加入jar塊(最后一塊代碼塊)
apply plugin: 'java'
apply plugin: 'maven'
group = 'com.alibaba.p3c'
version = '1.3.6'
description = """p3c-pmd"""
sourceCompatibility = 1.7
targetCompatibility = 1.7
tasks.withType(JavaCompile) {
options.encoding = 'UTF-8'
}
configurations.all {
}
repositories {
maven { url "https://oss.sonatype.org/content/repositories/snapshots" }
maven { url "http://repo.maven.apache.org/maven2" }
}
dependencies {
compile group: 'net.sourceforge.pmd', name: 'pmd-java', version:'5.5.2'
compile group: 'net.sourceforge.pmd', name: 'pmd-vm', version:'5.5.2'
testCompile group: 'net.sourceforge.pmd', name: 'pmd-test', version:'5.5.2'
}
jar {
from {
// 添加依懶到打包文件
configurations.runtime.collect{zipTree(it)}
}
}
- 開始構建Gradle項目
Windows下:
cd /path/to/p3c-pmd/
gradlew.bat build
Linux下:
cd /path/to/p3c-pmd/
./gradlew build
- 構建完成后在build/libs/中會生成p3c-pmd-1.3.6.jar包,到此就獲取到了我們需要的胖Jar包了
- 為啥會有第7步,直接拿這個胖Jar去檢查文件的話,會出現(xiàn)如下問題:
java -cp p3c-pmd-1.3.6.jar net.sourceforge.pmd.PMD -d test.java -R rulesets/java/ali-comment.xml
執(zhí)行后報錯:
Exception in thread "main" java.lang.NullPointerException
at net.sourceforge.pmd.cli.PMDParameters.getLanguage(PMDParameters.java:223)
at net.sourceforge.pmd.cli.PMDParameters.transformParametersIntoConfiguration(PMDParameters.java:151)
at net.sourceforge.pmd.PMD.run(PMD.java:490)
at net.sourceforge.pmd.cli.PMDCommandLineInterface.run(PMDCommandLineInterface.java:167)
at net.sourceforge.pmd.PMD.main(PMD.java:477)
為啥空指針異常了,去查看PMD源碼,發(fā)現(xiàn)PMD獲取不到資源文件中的語言值。而這個資源文件在META-INFO中。上面的構建方式沒有去解決Jar包中META-INFO文件下的文件合并問題。每個依賴的jar包在合并時都是復制進來,這就導致了原先的PMD包中有net.sourceforge.pmd.cpd.Language和net.sourceforge.pmd.lang.Language這兩個文件,而p3c-pmd中也有這兩個文件,沖突了。
我們要做得就是將包解壓出來,然后確保這兩個文件都只有一份在META-INFO文件夾中,并且保證:
net.sourceforge.pmd.cpd.Language文件的值為
net.sourceforge.pmd.cpd.JavaLanguage
net.sourceforge.pmd.lang.Language文件的值為
net.sourceforge.pmd.lang.java.JavaLanguageModule
最后重新打成Jar包就好了。至此,生成的jar包才是正確可用的編碼規(guī)范檢查工具。
這里,很多人肯定用多了IDE,都已經忘記java中jar包基本的操作了,這里附上Jar包基本的操作傳送門。
還有,Java打Jar包的幾種方式。
檢查源碼
接下來就可以用生成的jar進行代碼檢查了
java -cp p3c-pmd-1.3.6.jar net.sourceforge.pmd.PMD -d E:\CodeRepos\data-server-test\data-server-core\src\main\java\com -R rulesets/java/ali-comment.xml
E:\CodeRepos\data-server-test\data-server-core\src\main\java\com\jiniutech\common\BeanConvert.java:6: 【BeanConvert】 注釋缺少@author信息
E:\CodeRepos\data-server-test\data-server-core\src\main\java\com\jiniutech\common\BeanConvert.java:7: 接口方法【getBean】必須使用javadoc注釋
參數(shù)解釋:
- -d 源碼目錄,多個文件或者目錄以,號分開
- -R 指定規(guī)則,多個規(guī)則以,號分開。阿里規(guī)則路徑在包中rulesets/java/ali-*.xml
- -f 報告格式,text html xml等。
集成到GitLab的hooks中
hook機制在很多系統(tǒng)中都有,hook機制使得GitLab能在特定的重要動作發(fā)生前/時/后觸發(fā)自定義的腳本。GitLab在每次項目init時,就會在每一個項目里創(chuàng)建一個hooks文件夾的軟鏈接,指向一個特定文件夾。所以在hooks里的操作都是全局操作,是面向所有項目的。
[root@localhost data-server.git]# ll -la
total 32
lrwxrwxrwx. 1 polkitd root 47 Oct 25 02:43 hooks -> /opt/gitlab/embedded/service/gitlab-shell/hooks
由于我們想要達到的效果是每次提交前進行代碼檢查,因此要用到pre-receive文件,首先將p3c-pmd-1.3.6.jar 包復制到hooks中,然后在hooks中創(chuàng)建pre-receive文件,內容如下:
#!/bin/sh
#
REJECT=0
while read oldrev newrev refname; do
if [ "$oldrev" = "0000000000000000000000000000000000000000" ];then
oldrev="${newrev}^"
fi
files=`git diff --name-only ${oldrev} ${newrev} | grep -e "\.java$"`
if [ -n "$files" ]; then
TEMPDIR="tmp"
for file in ${files}; do
mkdir -p "${TEMPDIR}/`dirname ${file}`" >/dev/null
git show $newrev:$file > ${TEMPDIR}/${file}
done;
files_to_check=`find $TEMPDIR -name '*.java'`
/home/jdk1.8.0_191/bin/java -cp hooks/p3c-pmd-1.3.6.jar net.sourceforge.pmd.PMD -d ${files_to_check} -R rulesets/java/ali-comment.xml,rulesets/java/ali-concurrent.xml,rulesets/java/ali-constant.xml,rulesets/java/ali-exception.xml,rulesets/java/ali-flowcontrol.xml,rulesets/java/ali-naming.xml,rulesets/java/ali-oop.xml,rulesets/java/ali-orm.xml,rulesets/java/ali-other.xml,rulesets/java/ali-set.xml -f text
REJECT=$?
rm -rf $TEMPDIR
fi
done
exit $REJECT
要注意的是pre-receive文件必須沒有任何后綴,且為可執(zhí)行文件(+X)。
這個腳本在每次提交前檢查所有提交的后綴名.java的文件,然后用得到的p3c-pmd-1.3.6.jar 包對這些文件進行代碼檢查,然后返回結果。如果存在不規(guī)范的代碼則返回給提交者錯誤信息,如下圖

這樣強制進行代碼檢查就完成了。