代碼不只是用來運(yùn)行的犁功,更是用來閱讀的
編碼規(guī)范
代碼規(guī)范看似只是簡單的一個(gè)編碼的規(guī)范氓轰,對代碼格式、變量命名浸卦、注釋格式等做一個(gè)統(tǒng)一規(guī)范署鸡,看似有點(diǎn)強(qiáng)迫你改變編碼風(fēng)格的味道。但是當(dāng)你和許多團(tuán)隊(duì)協(xié)同開發(fā)過許多項(xiàng)目限嫌,寫過許多代碼之后再回頭來看的話靴庆,你就會發(fā)現(xiàn)它真的就是個(gè)規(guī)范,啊不怒医,真的是個(gè)好東西炉抒。有沒有看過國慶閱兵上的方陣,當(dāng)所有軍人著裝統(tǒng)一裆熙,排列整齊端礼,一起從長安街走過得時(shí)候,會不會被他們帶來的視覺沖擊所震撼入录。編碼規(guī)范就如其中的軍規(guī)蛤奥,當(dāng)大量的代碼都具有統(tǒng)一性整齊性時(shí),帶給每個(gè)參與的人的視覺效果也是極具沖擊性的僚稿。當(dāng)然除了視覺效果凡桥,愉悅了心情之外,這種統(tǒng)一性蚀同,為每個(gè)參與編碼的人員統(tǒng)一了風(fēng)格缅刽,彼此之間互相閱讀代碼的效率就高了啊掏,團(tuán)隊(duì)間的協(xié)作效率也就高了。常見的比較受認(rèn)可的編碼規(guī)范衰猛,基本都是大廠的(廢話迟蜜,沒點(diǎn)頭銜在高傲的程序猿前誰會服誰),例如:Google啡省、Sun娜睛、阿里巴巴等大廠都有發(fā)布自己的編碼規(guī)范,這些可都是集萬千大神的工程實(shí)踐總結(jié)卦睹,這些總結(jié)幫助行業(yè)人員提高了開發(fā)質(zhì)量和效率畦戒,大大降低了代碼的維護(hù)成本。
阿里巴巴JAVA編碼規(guī)范
好多大廠都發(fā)布了編碼規(guī)范结序,為何選阿里巴巴的呢障斋?第一,阿里給的規(guī)范更加符合國人的習(xí)慣徐鹤,畢竟里面絕大部分都是國人垃环;第二就是阿里的規(guī)范文檔都是中文的,方便閱讀返敬,也降低了一些翻譯的歧義性等等晴裹。(真實(shí)理由其實(shí)就一個(gè),我英文不好)有用過谷歌規(guī)范的再去用阿里的就會深有體會了救赐,谷歌的規(guī)范畢竟比較符合西方人習(xí)慣,很多注釋上的規(guī)范很蛋疼的只磷。
阿里巴巴的JAVA編程規(guī)范经磅,至今為止已更迭了多個(gè)版本,2018年6月6日钮追,《阿里巴巴Java開發(fā)手冊(詳盡版)》v1.4正式在GitHub上發(fā)布预厌,這是史上內(nèi)容最全、修正最為徹底的一個(gè)版本元媚,并且增加了單元測試規(guī)約內(nèi)容轧叽,這也是阿里官方對外發(fā)布的最后一個(gè)PDF版本,值得收藏刊棕。
《阿里巴巴Java開發(fā)手冊》是阿里內(nèi)部Java工程師所遵循的開發(fā)規(guī)范炭晒,涵蓋編程規(guī)約、單元測試規(guī)約甥角、異常日志規(guī)約网严、MySQL規(guī)約、工程規(guī)約嗤无、安全規(guī)約等震束,這是近萬名阿里Java技術(shù)精英的經(jīng)驗(yàn)總結(jié)怜庸,并經(jīng)歷了多次大規(guī)模一線實(shí)戰(zhàn)檢驗(yàn)及完善。這是阿里回饋給Java社區(qū)的一份禮物垢村,希望能夠幫助企業(yè)開發(fā)團(tuán)隊(duì)在Java開發(fā)上更高效割疾、容錯(cuò)、有協(xié)作性嘉栓,提高代碼質(zhì)量宏榕,降低項(xiàng)目維護(hù)成本。
這里是阿里巴巴Java編碼規(guī)范的GitHub傳送門胸懈。里面提供了多種代碼規(guī)范檢測方式:
- IntelliJ IDEA插件集成方式
- Eclipse 插件集成方式
- pmd工具集成方式
對應(yīng)的IDE插件可以看一下這篇文章《阿里巴巴Java開發(fā)規(guī)約插件p3c詳細(xì)教程及使用感受》
為了和GitLab能夠配合担扑,進(jìn)行提交時(shí)自動化得代碼檢查,這邊選擇了第三種pmd工具集成方式趣钱。
打成PMD工具Jar包
由于阿里的GitHub中p3c/p3c-pmd提供的只是規(guī)則代碼涌献,主體PMD代碼是以依賴方式引入,要把它制作成一個(gè)可獨(dú)立運(yùn)行的工具包首有,需要將所有依賴的包都封裝到一起燕垃,打成一個(gè)胖Jar包,才能夠在本地獨(dú)立得運(yùn)行井联。
- 從GitHub中把p3c的代碼庫下載下來(可用git clone也可以直接在GitHub中下載zip包)
- 安裝Gradle
- 進(jìn)入到p3c-pmd目錄中卜壕,初始化Gradle項(xiàng)目
# 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)}
}
}
- 開始構(gòu)建Gradle項(xiàng)目
Windows下:
cd /path/to/p3c-pmd/
gradlew.bat build
Linux下:
cd /path/to/p3c-pmd/
./gradlew build
- 構(gòu)建完成后在build/libs/中會生成p3c-pmd-1.3.6.jar包烙常,到此就獲取到了我們需要的胖Jar包了
- 為啥會有第7步轴捎,直接拿這個(gè)胖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í)行后報(bào)錯(cuò):
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獲取不到資源文件中的語言值。而這個(gè)資源文件在META-INFO中驼鞭。上面的構(gòu)建方式?jīng)]有去解決Jar包中META-INFO文件下的文件合并問題秦驯。每個(gè)依賴的jar包在合并時(shí)都是復(fù)制進(jìn)來,這就導(dǎo)致了原先的PMD包中有net.sourceforge.pmd.cpd.Language和net.sourceforge.pmd.lang.Language這兩個(gè)文件挣棕,而p3c-pmd中也有這兩個(gè)文件译隘,沖突了。
我們要做得就是將包解壓出來洛心,然后確保這兩個(gè)文件都只有一份在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,都已經(jīng)忘記java中jar包基本的操作了璧瞬,這里附上Jar包基本的操作傳送門户辫。
還有,Java打Jar包的幾種方式嗤锉。
檢查源碼
接下來就可以用生成的jar進(jìn)行代碼檢查了
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 源碼目錄渔欢,多個(gè)文件或者目錄以,號分開
- -R 指定規(guī)則,多個(gè)規(guī)則以,號分開瘟忱。阿里規(guī)則路徑在包中rulesets/java/ali-*.xml
- -f 報(bào)告格式奥额,text html xml等。
集成到GitLab的hooks中
hook機(jī)制在很多系統(tǒng)中都有访诱,hook機(jī)制使得GitLab能在特定的重要?jiǎng)幼靼l(fā)生前/時(shí)/后觸發(fā)自定義的腳本垫挨。GitLab在每次項(xiàng)目init時(shí),就會在每一個(gè)項(xiàng)目里創(chuàng)建一個(gè)hooks文件夾的軟鏈接触菜,指向一個(gè)特定文件夾九榔。所以在hooks里的操作都是全局操作,是面向所有項(xiàng)目的涡相。
[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
這里是GitLab Hooks的官方文檔哲泊。
由于我們想要達(dá)到的效果是每次提交前進(jìn)行代碼檢查,因此要用到pre-receive文件催蝗,首先將p3c-pmd-1.3.6.jar 包復(fù)制到hooks中切威,然后在hooks中創(chuàng)建pre-receive文件,內(nèi)容如下:
#!/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)先朦。
這個(gè)腳本在每次提交前檢查所有提交的后綴名.java的文件,然后用得到的p3c-pmd-1.3.6.jar 包對這些文件進(jìn)行代碼檢查犬缨,然后返回結(jié)果烙无。如果存在不規(guī)范的代碼則返回給提交者錯(cuò)誤信息,如下圖
這樣強(qiáng)制進(jìn)行代碼檢查就完成了遍尺。