2021阿里巴巴Java開發(fā)手冊1.4_第1頁
2021阿里巴巴Java開發(fā)手冊1.4_第2頁
2021阿里巴巴Java開發(fā)手冊1.4_第3頁
2021阿里巴巴Java開發(fā)手冊1.4_第4頁
2021阿里巴巴Java開發(fā)手冊1.4_第5頁
已閱讀5頁,還剩36頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權,請進行舉報或認領

文檔簡介

阿里巴巴Java開發(fā)手冊1.4.0前言《阿里巴巴JavaJavaMySQL本手冊的旨在碼出高效,碼出質(zhì)量。現(xiàn)代軟件架構的復雜性需要協(xié)同開發(fā)完成,如何高效地協(xié)同呢?無規(guī)矩不成方圓,無規(guī)范難以協(xié)同,比如,制訂交通法規(guī)表面上是要限制行車權,實際上是保障公眾的人身安全,試想如果沒有限速,沒有紅綠燈,誰還敢上路行駛。對軟件來說,適當?shù)囊?guī)范和標準絕不是消滅代碼內(nèi)容的創(chuàng)造性、優(yōu)雅性,而是限制過度個性化,以一種普遍認可的統(tǒng)一方式一起做事,提升協(xié)作效率,降低溝通成本。代碼的字里行間流淌的是軟件系統(tǒng)的血液,質(zhì)量的提升是盡可能少踩坑,杜絕踩重復的坑,切實提升系統(tǒng)穩(wěn)定性,碼出質(zhì)量。目錄前言前言一、編程規(guī)約 1(一) 命名風格 1(二) 常量定義 3(三) 代碼格式 4(四) OOP規(guī)約 6(五) 集合處理 9(六) 并發(fā)處理 12(七) 控制語句 14(八) 注釋規(guī)約 16(九) 其它 18二、異常日志 19(一) 異常處理 19三、單元測試 22四、安全規(guī)約 24五、MySQL數(shù)據(jù)庫 25三、單元測試 22四、安全規(guī)約 24五、MySQL數(shù)據(jù)庫 25(一) 建表規(guī)約 25(二) 索引規(guī)約 26(三) SQL語句 28(四) ORM映射 29六、工程結(jié)構 31(一) 應用分層 31(二) 二方庫依賴 32(三) 服務器 33七、設計規(guī)約 35附1:版本歷史 37附2:專有名詞解釋 38(PDF左側(cè)導航欄) 阿里巴巴Java開發(fā)手冊 PAGEPAGE32/38Java開發(fā)手冊版本號制定團隊更新日期備注1.4.0阿里巴巴集團技術團隊2018.5.20增加設計規(guī)約(詳盡版)一、編程規(guī)約(一命名風格【強制】代碼中的命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結(jié)束反例:_name/name/$name/name_/name$/name 【強制】代碼中的命名嚴禁使用拼音與英文混合的方式,更不允許直接使用中文的方式。說明:正確的英文拼寫和語法可以讓閱讀者易于理解,避免歧義。注意,即使純拼音命名方式也要避免采用。正例:alibaba/taobao/youku/hangzhou等國際通用的名稱,可視同英文。反例:DaZhePromotion[打折]/getPingfenByName()[評分]/int某變量=3UpperCamelCaseDO/BO/DTO/VO/AO/PO/UID等。正例:MarcoPolo/UserDO/XmlService/TcpUdpDeal/TaPromotion反例:macroPolo/UserDo/XMLService/TCPUDPDeal/TAPromotionlowerCamelCase正例:localValue/getHttpMessage()/inputUserId正例:MAX_STOCK_COUNT反例:MAX_COUNTAbstractBase開頭;Exception結(jié)尾;Test正例:int[]arrayDemo;反例:在main參數(shù)中,使用Stringargs[]來定義。POJOis反例:BooleanisDeletedisDeleted(),RPCdeleted出異常。單數(shù)形式,但是類名如果有復數(shù)含義,類名可以使用復數(shù)形式。正例:應用工具類包名為com.alibaba.ai.util、類名為MessageUtils(此規(guī)則參考spring的框架結(jié)構)【強制】杜絕完全不規(guī)范的縮寫,避免望文不知義。AbsClass;condition組合來表達其意。正例:在JDK中,表達原子更新的類名為:AtomicReferenceFieldUpdater。反例:變量inta的隨意命名方式。說明:將設計模式體現(xiàn)在名字中,有利于閱讀者快速理解架構設計理念。正例:publicclassOrderFactory;publicclassLoginProxy;publicclassResourceObserver;(publicJavadoc與接口方法相關,并且是整個應用的基礎常量。正例:接口方法簽名voidcommit();接口基礎常量StringCOMPANY="alibaba";反例:接口方法定義publicabstractvoidf();說明:JDK8default認實現(xiàn)。接口和實現(xiàn)類的命名有兩套規(guī)則:ServiceDAOSOAImpl正例:CacheServiceImplCacheService接口。(通常是–able的形式正例:AbstractTranslator實現(xiàn)Translatable。Enum說明:枚舉其實就是特殊的類,域成員均為常量,且構造方法被默認強制是私有。正例:ProcessStatusEnum的SUCCESS/UNKNOWN_REASON?!緟⒖肌扛鲗用?guī)約:Service/DAOget做前綴。list做前綴,復數(shù)形式結(jié)尾如:listObjects。count做前綴。4)save/insert做前綴。5)remove/delete6)update做前綴。領域模型命名規(guī)約數(shù)據(jù)對象:xxxDO,xxx數(shù)據(jù)傳輸對象:xxxDTO,xxx展示對象:xxxVO,xxxPOJODO/DTO/BO/VOxxxPOJO。(二常量定義【強制】不允許任何魔法值(即未經(jīng)預先定義的常量)反例:Stringkey"Id#taobao_"+tradeId;cache.put(key,value);longLongLl1混淆,造成誤解。說明:Longa2l;21Long2?【推薦】不要使用一個常量類維護所有常量,要按常量功能進行歸類,分開維護。正例:CacheConsts下ConfigConsts下。內(nèi)共享常量、類內(nèi)共享常量。client.jarconstant目錄下。constant目錄下。反例:易懂變量也要統(tǒng)一定義成應用內(nèi)共享常量,兩位攻城師在兩個類中分別定義了表示“是”的變量:A中:publicstaticfinalStringYESyes";類B中:publicstaticfinalStringYES="y";A.YES.equals(B.YES)truefalse,導致線上問題。constant目錄下。constant目錄下。privatestaticfinal定義?!就扑]】enum類型來定義。enum示一年中的第幾個季節(jié)。正例:publicenumSeasonEnum{SPRING(1),SUMMER(2),AUTUMN(3),WINTER(4);privateintseq;SeasonEnum(intseq){this.seq=seq;}}(三代碼格式{}是非空代碼塊則:左大括號前不換行。左大括號后換行。右大括號前換行。else等代碼則不換行表示終止的右大括號后必須換行。;5條下方正例提示。反例:ifab空格)【強制】if/for/while/switch/do【強制】任何二目、三目運算符的左右兩邊都需要加一個空格。說明:運算符包括賦值運算符=、邏輯運算符&&、加減乘除符號等。4tab說明:tab1tab4個空格。IDEAtab4個空格時,Usetabcharactereclipseinsertspacesfortabs。正例:(1-5點)publicstaticvoidmain(String[]args){//4個空格Stringsay="hello";//運算符的左右必須有一個空格intflag=0;//iff與左括號,0與右括號不需要空格if(flag==0){System.out.println(say);}//左大括號前加空格且不換行;左大括號后換行if(flag==1){System.out.println("world");//右大括號前換行,右大括號后有else,不用換行}else{System.out.println("ok");//在右大括號后直接結(jié)束,則必須換行}}正例://這是示例注釋,請注意在雙斜線之后有一個空格Stringygb=newString();12042)運算符與下文一起換行。方法調(diào)用的點符號與下文一起換行。方法調(diào)用中的多個參數(shù)需要換行時,在逗號后進行。正例:StringBuffersb=newStringBuffer();//1204個空格,點號和方法名稱一起換行sb.append("zi").append("xin")append("huang")append("huang")append("huang");反例:StringBuffersb=newStringBuffer();//120括號前換行sb.append("zi").append("xin")...append("huang");//120個字符,不要在逗號前換行method(args1,args2,args3,...,argsX);正例:args1,后邊必須要有一個空格。method(args1,args2,args3);【強制】IDEtextfileencodingUTF-8;IDEUnixWindows80行。80行。正例:代碼邏輯分清紅花和綠葉,個性和共性,綠葉邏輯單獨出來成為額外方法,使主干代碼更加清晰;共性邏輯抽取成為共性方法,便于復用和維護。正例:intone=1;longtwo=2L;floatthree=3F;StringBuffersb=newStringBuffer();說明:sba、bc情況下,是非常累贅的事情。說明:任何情形,沒有必要插入多個空行進行隔開。(四OOP規(guī)約本,直接用類名來訪問即可。【強制】所有的覆寫方法,必須加@Override注解。get0bject()@Override譯報錯。JavaObject說明:可變參數(shù)必須放置在參數(shù)列表的最后。(提倡同學們盡量不用可變參數(shù)編程)正例:publicList<User>listUsers(Stringtype,Long...ids){...}影響。接口過時必須加@Deprecated【強制】不能使用過時的類或方法。說明:.URLDecoderdecode(StringencodeStrdecode(StringsourceStringencode)【強制】Objectequalsequals。正例:"test".equals(object);反例:object.equals("test");說明:java.util.Objects#equals(JDK7引入的工具類)【強制】所有的相同類型的包裝類對象之間值的比較equals說明:Integervar=?在-128127范圍內(nèi)的賦值,Integer對象是在IntegerCache.cacheInteger值可以直接使用==進行equals關于基本數(shù)據(jù)類型與包裝數(shù)據(jù)類型的使用標準如下:POJO【強制】RPC【推薦】所有的局部變量使用基本數(shù)據(jù)類型。說明:POJONPE正例:nullNPEx%,xRPC0%,這是不合理的,應該顯示成中劃線。所以包裝nullDO/DTO/VOPOJO默認值。反例:POJOgmtCreatenewDate(),serialVersionUID;如serialVersionUID值。說明:serialVersionUIDinit方法中。【強制】POJOtoStringIDE中的工具:sourcegeneratetoStringPOJOsuper.toString。POJOtoString()POJOxxxisXxx()getXxx()方法。說明:xxxStringsplitIndexOutOfBoundsException的風險。說明:Stringstr="a,b,c,,";String[]ary=str.split(",");//預期大于3,結(jié)果是3System.out.println(ary.length);16條規(guī)則。私有方法getter/setter方法。“模板設計模式”下的核心方法黑盒實現(xiàn);ServiceDAOgetter/setter【推薦】setterthis.成員名參數(shù)名。在getter/setter反例:publicIntegergetData()if(condition){returnthis.data+100;}else{returnthis.data-100;}}StringBuilderappend方法進行擴展。說明:newStringBuilderappendtoStringStringStringstr="start";for(inti=0;i<100;i++)str=str+"hello";}finalfinal不允許被繼承的類,如:String類。不允許修改引用的域?qū)ο蟆2辉试S被重寫的方法,如:POJO類的setter方法。不允許運行過程中重新賦值的局部變量。final地進行重構。Objectclone說明:cloneclone深度遍歷式拷貝?!就扑]】類成員與方法訪問控制從嚴:newprivate。publicdefaultstaticprotected4)staticprivate。5)staticprivate。6)tected。說明:任何類、方法、參數(shù)、變量,嚴控訪問范圍。過于寬泛的訪問范圍,不利于模塊解耦。privatepublicservice成員(五集合處理hashCodeequalsequalshashCode。SethashCodeequalsSet存儲的對象必須重寫這兩個方法。MaphashCodeequals。說明:String重寫了hashCodeequalsStringkey來使用。AraLst的suLst結(jié)果不可強轉(zhuǎn)成AryitCasatxeionjava.util.RandomAccessSubListcannotbecasttojava.util.ArrayList。suLstAraLstSuLstrryitAryitSubListsubList高度注意ConcurrentModificationException異常。toArray(Tarray)list.size()。toArray[list.size()]null正例:List<String>list=newArrayList<String>(2);list.add("guan");list.add("bao");String[]array=newString[list.size()];array=list.toArray(array);反例:toArrayObject[]ClassCastException錯誤。Arrays.asList()add/remove/clearUnsupportedOperationException異常。aLstArasArysaist體現(xiàn)的是適配器模式,只是轉(zhuǎn)換接口,后臺的數(shù)據(jù)仍是數(shù)組。String[]str=newString[]{"you","wu"};Listlist=Arrays.asList(str);第一種情況:list.add("yangguanbao");運行時異常。第二種情況:str[0]="gujin";那么list.get(0)也會隨之修改?!緩娭啤糠盒屯ㄅ浞鹐xtendsT>add方法,而superT>get說明:PECS(ProducerExtendsConsumerSuper)extendsT><?superT>。foreach循環(huán)里進行元素的remove/addremoveIteratorIterator正例:List<String>list=newArrayList<>();list.add("1");list.add("2");Iterator<String>iterator=list.iterator();while(iterator.hasNext()){Stringitem=iterator.next();if(刪除元素的條件){iterator.remove();}}反例:for(Stringitem:list){if("1".equals(item))list.remove(item);}}說明:以上代碼的執(zhí)行結(jié)果肯定會出乎大家的意料,那么試一下把“1”換成“2”,會是同樣的結(jié)果嗎?JDK7Arrays.sort,Collections.sortIllegalArgumentException異常。說明:三個條件如下x,yy,xx>y,y>z,則x>z。x=y,則x,zy,z反例:下例中沒有處理相等的情況,實際使用中可能會出現(xiàn)異常:newComparator<Student>(){@Overridepublicintcompare(Studento1,Studento2)returno1.getId()>o2.getId()?1:}}; JDK7diamond說明:diamond,直接使用<>來指代前邊已經(jīng)指定的類型。正例://diamond方式HashMap<String,String>userCache=newHashMap<>(16);//全省略方式ArrayList<User>users=newArrayList(10);【推薦】集合初始化時,指定集合初始值大小。說明:HashMapHashMap(intinitialCapacity初始化。intaCpcy(需要存儲的元素個數(shù)/負載因子)+1(loaderfactor)0.75,16(。反例:HashMap10247次被迫擴大,resizehashentrySetMap類集合KVkeySet說明:keySet2IteratorhashMapvalueentrySetkeyvalueentryJDK8Map.foreach方法。V值集合,是一個list集合對象;keySet()KSet集合對象;entrySet()K-V值組合集合。MapK/Vnull集合類KeyValueSuper說明Hashtable不允許為null不允許為nullDictionary線程安全ConcurrentHashMap不允許為null不允許為nullAbstractMap鎖分段技術(JDK8:CAS)TreeMap不允許為null允許為nullAbstractMap線程不安全HashMap允許為null允許為nullAbstractMap線程不安全HashMapConcurrentHashMapnull值,而事實上,nullNPE異常。(sort)(order)(unsort)和不穩(wěn)定性(unorder)序是一定的。如:ArrayListorder/unsort;HashMapunorder/unsort;TreeSet是order/sort。SetList的contains(六并發(fā)處理說明:資源驅(qū)動類、工具類、單例工廠類都需要注意。正例:publicclassTimerTaskThreadextendsThreadpublicTimerTaskThread(){super.setName("TimerTaskThread");...}}【強制】線程資源必須通過線程池提供,不允許在應用中自行顯式創(chuàng)建線程。者“過度切換”的問題。ExecutorsThreadPoolExecutor說明:ExecutorsFixedThreadPoolSingleThreadPool:允許的請求隊列長度為Integer.MAX_VALUE,可能會堆積大量的請求,從而導致OOM。CachedThreadPoolScheduledThreadPool:允許的創(chuàng)建線程數(shù)量為Integer.MAX_VALUE,可能會創(chuàng)建大量的線程,從而導致OOM?!緩娭啤縎impleDateFormatstaticstaticDateUtils正例:注意線程安全,使用DateUtils。亦推薦如下處理:privatestaticfinalThreadLocal<DateFormat>df=newThreadLocal<DateFormat>(){@OverrideprotectedDateFormatinitialValue(){returnnewSimpleDateFormat("yyyy-MM-dd");}};說明:JDK8InstantDate,LocalDateTimeCalendar,DateTimeFormatterSimpleDateFormat,官方給出的解釋:simplebeautifulstrongimmutablethread-safe。;鎖區(qū)塊,就不要鎖整個方法體;能用對象鎖,就不要用類鎖。說明:盡可能使加鎖的代碼塊工作量盡可能的小,避免在鎖代碼塊中調(diào)用RPC方法。成死鎖。ABCA、B、Cversion作為更新依據(jù)。3次?!緩娭啤慷嗑€程并行處理定時任務時,TimerTimeTaskScheduledExecutorServiceCountDownLatchcountDowncatchcountDown方法被執(zhí)行到,避免主線程無法執(zhí)行await說明:try-catch到。Random實例被多線程使用,雖然共享該實例是線程安全的,但會因競爭同一seed導致的性能下降。說明:Randomjava.util.Random的實例或者Math.random()的方式。正例:JDK7APIThreadLocalRandom,而在JDK7【推薦】在并發(fā)場景下,通過雙重檢查鎖(double-checkedlocking)The"Double-CheckedLockingisBrokenDeclaration),推薦解決方案中較為簡單一種(JDK5),將目標屬性聲明為volatile。反例:classLazyInitDemo{privateHelperhelper=publicHelpergetHelper(){if(helper==null)synchronized(this)if(helper==null)helper=newHelper();}returnhelper;}//othermethodsandfields...}【參考】volatilecount++countnewAtomicInteger();count.addAndGet(1JDK8LongAdderAtomicLong(減少樂觀鎖的重試次數(shù))。HashMapresizeCPU開發(fā)過程中可以使用其它數(shù)據(jù)結(jié)構或加鎖來規(guī)避此風險?!緟⒖肌縏hreadLocal無法解決共享對象的更新問題,ThreadLocalstatic(要是這個線程內(nèi)定義的)都可以操控這個變量。(七控制語句switchcasebreak/returncase;switchdefaultif/else/for/while/do(condition)statements;【強制】在高并發(fā)場景中,避免使用”等于”說明:如果并發(fā)控制沒有處理好,容易產(chǎn)生等值判斷被“擊穿”的情況,使用大于或小于的區(qū)間判斷條件來代替。0成了負數(shù),這樣的話,活動無法終止。if-else,這種方式可以改寫成:if(condition){...returnobj;}//else;說明:if()...elseif()...else...3層。3if-else其中衛(wèi)語句示例如下:publicvoidtoday()if(isBusy()){System.out.println(“changetime.”);return;}if(isFree()){System.out.println(“gototravel.”);return;}System.out.println(“stayathometolearnAlibabaJavaCodingGuidelines.”);return;}【推薦】除常用方法(getXxx/isXxx)復雜邏輯判斷的結(jié)果賦值給一個有意義的布爾變量名,以提高可讀性。if樣的條件執(zhí)行什么樣的語句,那么,如果閱讀者分析邏輯表達式錯誤呢?正例://偽代碼如下finalbooleanexisted=(file.open(fileName,"w")!=null)&&(...)||if(existed){...}反例:if((file.open(fileName,"w")!=null)&&(...)||(...)){...}try-catch(try-catch是否可以移至循環(huán)體外?!就扑]】避免采用取反邏輯運算符。說明:正例:if(x628)x628。反例:if(!(x628))來表達x628。【推薦】接口入?yún)⒈Wo,這種場景常見的是用作批量操作的接口?!緟⒖肌肯铝星樾?,需要進行參數(shù)校驗:調(diào)用頻次低的方法。數(shù)錯誤導致中間執(zhí)行回退,或者錯誤,那得不償失。需要極高穩(wěn)定性和可用性的方法。RPC/API/HTTP接口。敏感權限入口?!緟⒖肌肯铝星樾?,不需要進行參數(shù)校驗:極有可能被循環(huán)調(diào)用的方法。但在方法說明里必須注明外部參數(shù)檢查要求。DAOServiceDAOprivate數(shù)已經(jīng)做過檢查或者肯定不會有問題,此時可以不校驗參數(shù)。(八注釋規(guī)約Javadoc/**內(nèi)容*///xxx方式。IDEJavadocIDE閱讀效率?!緩娭啤克械某橄蠓椒ǎòń涌谥械姆椒ǎ㎎avadoc注釋、除了返回值、參數(shù)、異常說明外,還必須指出該方法做什么事情,實現(xiàn)什么功能。說明:對子類的實現(xiàn)要求,或者調(diào)用注意事項,請一并說明?!緩娭啤克械念惗急仨毺砑觿?chuàng)建者和創(chuàng)建日期。【強制】方法內(nèi)部單行注釋,在被注釋語句上方另起一行,使用//使用/**/注釋,注意與代碼對齊?!緩娭啤克械拿杜e類型字段必須要有注釋,說明每個數(shù)據(jù)項的用途?!就扑]】與其“半吊子”英文原文即可。反例:“TCP連接超時解釋成“傳輸控制協(xié)議連接超時”,理解反而費腦筋。等的修改。就失去了導航的意義?!緟⒖肌恐斏髯⑨尩舸a。在上方詳細說明,而不是簡單地注釋掉。如果無用,則刪除。說明:代碼被注釋掉有兩種可能性:1)后續(xù)會恢復此段代碼邏輯。2)永久不用。前者如果沒有備注信息,難以知曉注釋動機。后者建議直接刪掉(代碼倉庫保存了歷史代碼)。;;的,使其能夠快速接替自己的工作。一個極端:過多過濫的注釋,代碼的邏輯一旦修改,修改注釋是相當大的負擔。反例://putelephantintoput(elephant,fridge);elephant義清晰的代碼不需要額外的注釋。經(jīng)常清理此類標記。線上故障有時候就是來源于這些標記處的代碼。1)待辦事宜(TODO):(標記人,標記時間,[預計處理時間])Javadoc(Javadoc標簽。2)錯誤,不能工作(FIXME):([預計處理時間])FIXME標記某代碼是錯誤的,而且不能工作,需要及時糾正的情況。(九其它說明:不要在方法體內(nèi)定義:PatternpatternPpile(“規(guī)則”);velocityPOJOPOJOgetXxx()boolean基本數(shù)據(jù)類型變量(booleanis前綴)isXxx()方法。說明:BooleangetXxx()【強制】后臺輸送給頁面的變量必須加$!{var}——中間的感嘆號。說明:varnull或者不存在,那么${var}Math.randomdouble0≤x<1(能夠取到零值,注意除零異常)x10RandomnextIntnextLong方法。System.currentTimeMillis而不是newDate().getTime();說明:System.nanoTime()JDK8Instant類?!就扑]】不要在視圖模板中加入任何復雜的邏輯。說明:根據(jù)MVC理論,視圖的職責是展示,不要搶模型和控制器的活?!就扑]】任何數(shù)據(jù)結(jié)構的構造或初始化,都應指定大小,避免數(shù)據(jù)結(jié)構無限增長吃光內(nèi)存。【推薦】及時清理不再使用的代碼段或配置信息。說明:對于垃圾代碼或過時配置,堅決清理干凈,避免程序過度臃腫,代碼冗余。個斜杠(///)來說明注釋掉代碼的理由。二、異常日志(一異常處理【強制】JavaRuntimeExceptionNullPointerException,IndexOutOfBoundsException等等。說明:catchNumberFormatException來實現(xiàn)。正例:if(obj!=null){...}反例:try{obj.method();}catch(NullPointerExceptione){…}【強制】異常不要用來做流程控制,條件控制。說明:異常設計的初衷是解決程序運行中的各種意外情況,且異常的處理效率比條件判斷方式要低很多?!緩娭啤縞atch時請分清穩(wěn)定代碼和非穩(wěn)定代碼,穩(wěn)定代碼指的是無論如何不會出錯的代碼。catch于定位問題,這是一種不負責任的表現(xiàn)。簡單,在程序上作出分門別類的判斷,并提示給用戶。內(nèi)容。try滾事務?!緩娭啤縡inallytry-catch。說明:JDK7try-with-resources方式。finallyreturn。說明:finallyreturntryreturn說明:如果預期對方拋的是繡球,實際接到的是鉛球,就會產(chǎn)生意外情況?!就扑]】方法的nullnull值。本手冊明確NPE者來說,也并非高枕無憂,必須考慮到遠程調(diào)用失敗、序列化失敗、運行時異常等場景返回null的情況。NPENPE產(chǎn)生的場景:返回類型為基本數(shù)據(jù)類型,returnNPE反例:publicintf()returnInteger對象},如果為nullNPE。null。isNotEmptynull。NPE。SessionNPE檢查,避免空指針。obj.getA().getB().getC();NPE。正例:JDK8OptionalNPE問題。unchecked/checkednewRuntimeException(),Exception/ServiceException等。http/api“錯誤碼”;而應用內(nèi)部推薦異常拋出;RPCResult方式isSuccess()、“錯誤碼”、“錯誤簡短信息”。說明:RPCResult使用拋異常返回方式,調(diào)用方如果沒有捕獲到就會產(chǎn)生運行時錯誤。newerrormessage的性能損耗也是問題?!緟⒖肌勘苊獬霈F(xiàn)重復的代碼(Don’tRepeatYourself)DRY原則。說明:隨意復制和粘貼代碼,必然會導致代碼的重復,在以后需要修改時,需要修改所有的副本,容易遺漏。必要時抽取共性方法,或者抽象公共類,甚至是組件化。publicprivatebooleancheckParam(DTOdto){...}(二日志規(guī)約(Log4jLogback)APIimportorg.slf4j.Logger;importorg.slf4j.LoggerFactory;privatestaticfinalLoggerlogger=LoggerFactory.getLogger(Abc.class);15天,因為有些異常具備以“周”為頻次發(fā)生的特點?!緩娭啤繎弥械臄U展日志(如打點、臨時監(jiān)控、訪問日志等)命名方式:appName_logType_logName.log。logType:stats/monitor/access;logName:正例:mppservermppserver_monitor_timeZoneConvert.log說明:推薦對日志進行分類,如將錯誤日志和業(yè)務日志分開存放,便于開發(fā)人員查看,也便于通過日志對系統(tǒng)進行及時監(jiān)控。trace/debug/info說明:logger.debug("Processingtradewithididandsymbolsymbol);wansmoltoString()(條件)if(logger.isDebugEnabled()){logger.debug("Processingtradewithid:"+id+"andsymbol:"+symbol);}正例:(占位符)logger.debug("Processingtradewithid:{}andsymbol:{}",id,symbol);log4j.xmladditivity=false。正例:<loggername="com.taobao.dubbo.config"additivity="false">throws往上拋出。正例:logger.error(各類參數(shù)或者對象toString()+"_"+e.getMessage(),e);debug日志;info;warn撐爆,并記得及時刪除這些觀察日志。說明:大量地輸出無效日志,不利于系統(tǒng)性能提升,也不利于快速定位錯誤點。記錄日志時請思考:這些日志真的有人看嗎?看到這條日志你能做什么?能不能給問題排查帶來好處?warnerror說明:注意日志輸出的級別,error級別只記錄系統(tǒng)邏輯出錯、異?;蛘咧匾腻e誤信息。使用全英文來注釋和描述日志錯誤信息。三、單元測試AIR原則。說明:單元測試在線上運行時,感覺像空氣(AIR)一樣并不存在,但在測試質(zhì)量的保障上,卻是非常關鍵的。好的單元測試宏觀上來說,具有自動化、獨立性、可重復執(zhí)行的特點。A:Automatic()I:Independent()R:Repeatable()System.outassert決不能互相調(diào)用,也不能依賴執(zhí)行的先后次序。反例:method2method1method2的輸入?!緩娭啤繂卧獪y試是可以重復執(zhí)行的,不能受到外界環(huán)境的影響。說明:checkin果單測對外部環(huán)境(網(wǎng)絡、服務、中間件等)有依賴,容易導致持續(xù)集成機制的不可用。SUTspringDI(內(nèi)存)Mock實現(xiàn)。別,一般是方法級別。說明:只有測試粒度小才能在出錯時盡快定位到出錯位置。單測不負責檢查跨類或者跨系統(tǒng)的交互邏輯,那是集成測試的領域。【強制】核心業(yè)務、核心應用、核心模塊的增量代碼確保單元測試通過。說明:新增代碼及時補充單元測試,如果新增代碼影響了原有單元測試,請及時修正。srcts/aa100%DAOManagerServiceBCDEB:BorderC:CorrectD:DesignEEror(到預期的結(jié)果?;蛘咧苯硬僮鲾?shù)據(jù)庫把數(shù)據(jù)插入進去,請使用程序插入或者導入數(shù)據(jù)的方式來準備數(shù)據(jù)。反例:刪除某一行數(shù)據(jù)的單元測試,在數(shù)據(jù)庫中,先直接手動增加一行作為刪除目標,但是這一行新增數(shù)據(jù)并不符合業(yè)務插入規(guī)則,導致測試結(jié)果異常。對單元測試產(chǎn)生的數(shù)據(jù)有明確的前后綴標識。正例:RDCRDC_UNIT_TEST_書寫不規(guī)范測試代碼。覆蓋所有測試用例。目提測前完成單元測試?!緟⒖肌繛榱烁奖愕剡M行單元測試,業(yè)務代碼應避免以下情況:構造方法中做的事情過多。存在過多的全局變量和靜態(tài)方法。存在過多的外部依賴。存在過多的條件語句。說明:多層條件語句建議使用衛(wèi)語句、策略模式、狀態(tài)模式等方式重構?!緟⒖肌坎灰獙卧獪y試存在如下誤解:那是測試同學干的事情。本文是開發(fā)手冊,凡是本文內(nèi)容都是與開發(fā)同學強相關的。單元測試代碼是多余的。系統(tǒng)的整體功能與各單元部件的測試正常與否是強相關的。單元測試代碼不需要維護。一年半載后,那么單元測試幾乎處于廢棄狀態(tài)。單元測試與線上故障沒有辯證關系。好的單元測試能夠最大限度地規(guī)避線上故障。四、安全規(guī)約【強制】隸屬于用戶個人的頁面或者功能必須進行權限控制校驗。說明:防止沒有做水平權限校驗就可隨意訪問、修改、刪除別人的數(shù)據(jù),比如查看他人的私信內(nèi)容、修改他人的訂單?!緩娭啤坑脩裘舾袛?shù)據(jù)禁止直接展示,必須對展示數(shù)據(jù)進行脫敏。說明:中國大陸個人手機號碼顯示為:158****91194位,防止隱私泄露。SQLMETADATASQL注入,SQL說明:忽略參數(shù)校驗可能導致:pagesizeorderby任意重定向SQL注入反序列化注入ReDoS說明:Java代碼用正則來驗證客戶端的輸入,有些正則寫法驗證普通用戶輸入沒有問題,但是如果攻擊人員使用的是特殊構造的字符串來驗證,有可能導致死循環(huán)的結(jié)果。HTML頁面輸出未經(jīng)安全過濾或未正確轉(zhuǎn)義的用戶數(shù)據(jù)。【強制】表單、AJAXCSRF說明:CSRF(Cross-siterequestforgery)跨站請求偽造是一類常見編程漏洞。對于存在CSRF漏洞的應用/URL不知情的情況下對數(shù)據(jù)庫中用戶參數(shù)進行相應修改。制,如數(shù)量限制、疲勞度控制、驗證碼校驗,避免被濫刷而導致資損。說明:如注冊時發(fā)送驗證碼到手機,如果沒有限制次數(shù)和頻率,那么可以利用此功能騷擾到其它用戶,并造成短信平臺資源浪費。濾等風控策略。五、MySQL數(shù)據(jù)庫(一建表規(guī)約is_xxxunsignedtinyint(1表示是,0表示否。說明:任何字段如果為非負數(shù),必須是unsigned。is<resultMap>設置is_xxxXxxtinyintis_xxx的命名方式是為了明確其取值含義與取值范圍。正例:表達邏輯刪除的字段名is_deleted,1表示刪除,0表示未刪除。,WindowsLinux正例:aliyun_admin,rdc_config,level3_name反例:AliyunAdmin,rdcConfig,level_3_name【強制】表名不使用復數(shù)名詞。說明:DO形式,符合表達習慣。desc、rangematch、delayedMySQL官方保留字。pk_uk_字段名;idx_字段名。說明:pk_primarykey;uk_uniquekey;idx_index的簡稱。decimalfloatdouble。說明:floatdoubledecimalchar【強制】varchar5000text【強制】表必備三字段:idgmt_creategmt_modified。說明:idbigintunsigned1。gmt_create,gmt_modifieddatetime【推薦】表的命名最好是加上“業(yè)務名稱_表的作用”。正例:alipay_task/force_project/trade_config【推薦】庫名與應用名稱盡量一致?!就扑]】如果修改字段含義或?qū)ψ侄伪硎镜臓顟B(tài)追加時,需要及時更新字段注釋?!就扑]】字段允許適當冗余,以提高查詢性能,但必須考慮數(shù)據(jù)一致。冗余字段應遵循:不是頻繁修改的字段。varchartext字段。正例:商品類目名稱使用頻率高,字段長度短,名稱基本一成不變,可在相關聯(lián)的表中冗余存儲類目名稱,避免關聯(lián)查詢。5002GB說明:如果預計三年后的數(shù)據(jù)量根本達不到這個級別,請不要在創(chuàng)建表時就分庫分表。索速度。正例:如下表,其中無符號值可以避免誤存負數(shù),且擴大了表示范圍。對象年齡區(qū)間類型字節(jié)表示范圍人150tinyintunsigned10255龜數(shù)百歲smallintunsigned2065535恐龍化石數(shù)千萬年intunsigned4042.9億太陽50億年bigintunsigned801019次方(二索引規(guī)約【強制】業(yè)務上具有唯一特性的字段,即使是多個字段的組合,也必須建成唯一索引。說明:insert然有臟數(shù)據(jù)產(chǎn)生。joinjoin說明:join也要注意表索引、SQL性能。varchar實際文本區(qū)分度決定索引長度即可。2090%count(distinctleft(列名))/count(*)【強制】頁面搜索嚴禁左模糊或者全模糊,如果需要請走搜索引擎來解決。B-Tree引。orderby有序性。orderbyfile_sort正例:wherea=?andborderbyc索引:a_b_c反例:索引中有范圍查找,那么索引有序性無法利用,如:WHEREa>10ORDERBYb;索引a_b無法排序?!就扑]】利用覆蓋索引來進行查詢操作,避免回表。說明:1111一下就好,這個目錄就是起到覆蓋索引的作用。explain的結(jié)果,extrausingindex?!就扑]】利用延遲關聯(lián)或者子查詢優(yōu)化超多分頁場景。說明:MySQLoffsetoffset+NoffsetoffsetSQL改寫。正例:idSELECTa.*FROM1a,(selectidfrom1where條件LIMIT100000,20bwherea.id=b.id【推薦】SQLrangerefconsts最好。說明:consts(ref(normalindex)。range反例:explaintype=indexindex級range【推薦】建組合索引的時候,區(qū)分度最高的在最左邊。正例:whereaandb,如果aidx_a索引即可。說明:存在非等號和等號混合時,在建索引時,請把等號條件的列前置。如:wherecdcdidx_d_c?!就扑]】防止因字段類型不同造成的隱式轉(zhuǎn)換,導致索引失效?!緟⒖肌縿?chuàng)建索引時避免有如下極端誤解:寧濫勿缺。認為一個查詢就需要建一個索引。寧缺勿濫。認為索引會消耗空間、嚴重拖慢更新和新增速度。抵制惟一索引。認為業(yè)務的惟一性一律需要在應用層通過“先查后插”方式解決。(三SQL語句count(列名)count(常量)SQL92NULLNULL無關。說明:count(*)NULLcount(列名)NULL值的行?!緩娭啤縞ount(distinctcolNULLcount(distinctcol1,col2NULL0。NULLsum(col)sum()NPE問題。正例:sumNPESELECTIF(ISNULL(SUM(g)),0,SUM(g))FROMtable;ISNULL()NULL說明:NULLNULL。NULL<>NULLNULLfalse。NULL=NULLNULLtrue。NULL<>1NULLtrue。count0【強制】不得使用外鍵與級聯(lián),一切外鍵概念必須在應用層解決。student_idstudent_idstudent_idstudent_id;【強制】禁止使用存儲過程,存儲過程難以調(diào)試和擴展,更沒有移植性?!緩娭啤繑?shù)據(jù)訂正(特別是刪除、修改記錄操作)select無誤才能執(zhí)行更新語句。inin1000個之內(nèi)。utf-8說明:SELECTLENGTH("輕松工作");返回為12SELECTCHARACTER_LENGTH("輕松工作");返回為4utf8mb4utf-8【參考】TRUNCATETABLEDELETETRUNCATE無事務且不觸發(fā)trigger,有可能造成事故,故不建議在開發(fā)代碼中使用此語句。說明:TRUNCATETABLE在功能上與不帶WHERE子句的DELETE語句相同。(四ORM映射*作為查詢的字段列表,需要哪些字段必須明確寫明。2)resultMaptext類型的字段。POJOisis_resultMap說明:POJO類以及數(shù)據(jù)庫字段定義規(guī)定,在<resultMap>中MyBatisGenerator生成的代碼中,需要進行對應的修改。resultClass要定義;POJO類與之對應。說明:DOsql.xml不要使用${}SQL【強制】iBATISqueryForList(StringstatementName,intstart,intsize)薦使用。其實現(xiàn)方式是在數(shù)據(jù)庫取到statementName對應的SQLsubListstart,size正例:Map<String,Object>map=newHashMap<>();map.put("start",start);map.put("size",size);HashMapHashtable說明:resultClass=”Hashtable”,會置入字段名和屬性值,但是值的類型不可控。gmt_modified字段值為當前時間。POJOupdatetablesetc1=value1,c2=value2,c3=value3;SQL時,不要更新無改動的字段,一是易出錯;二是效率低;binlog存儲?!緟⒖肌緻TransactionalQPS,另外使用事務的地方需要考慮各方面的回滾方案,包括緩存回滾、搜索引擎回滾、消息補償、統(tǒng)計修正等。<isEqual>compareValuenull時執(zhí)行;<isNotNull>null值時執(zhí)行。六、工程結(jié)構(一應用分層【推薦】圖中默認上層依賴于下層,箭頭關系表示可直接依賴,如:開放接口層可以依賴于WebService開放接口層ServiceRPC接口Webhttp網(wǎng)關安全控制、流量控制等。終端顯示層velocity渲染,JS渲染,JSP渲染,移動端展示等。Web層Service層Manager層對第三方平臺封裝的層,預處理返回結(jié)果及轉(zhuǎn)化異常信息;Service;DAODAODAO層MySQLOracle、Hbase外部接口或第三方平臺RPCHTTP接口?!緟⒖肌浚ǚ謱赢惓L幚硪?guī)約)DAOcatchcatch(Exceptione)thrownewDAOException(e)Manager/ServiceServiceManagerServiceServiceWeb和錯誤信息方式返回?!緟⒖肌糠謱宇I域模型規(guī)約:DO(DataDAODTO(DataTransferObject)ServiceManager向外傳輸?shù)膶ο?。BO(BusinessObject)ServiceWebServiceVO(ViewObject)WebQuery2Map類來傳輸。(二二方庫依賴GAVGroupID格式:com.{公司/BU}.[.]4級。{公司/BU}albbatoaomal/lepesU一級或com.alibaba.dubbo.registerArtifactID格式:產(chǎn)品線名-模塊名。語義不重復不遺漏,先到中央倉庫去查證一下。正例:dubbo-client/fastjson-api/jstorm-toolVersion【強制】二方庫版本號命名方式:主版本號.次版本號.修訂號主版本號API次版本號API不兼容修改。修訂號BUG0.0.1合理的版本號:1.3.4或1.4.0或2.0.0SNAPSHOT版本安全包除外)。SNAPSHOTjardependency:resolvedependency:tree<excludes>jar包。POJO對象?!緩娭啤恳蕾囉谝粋€二方庫群時,必須定義一個統(tǒng)一的版本變量,避免版本號不一致。說明:依賴springframework-core,-context,-beans,它們都是同一個版本,可以定義一個變量來保存版本:${spring.version},定義依賴的時候,引用該版本。pomGroupIdArtifactId,但是不同的Version。libpom<dependencies><dependencyManagement>語句塊中。scopepom<dependencies>pom的<dependencies>里的依賴都會自動引入,并默認被所有的子項目繼承?!就扑]】二方庫不要有配置項,最低限度不要再增加配置項?!緟⒖肌繛楸苊鈶枚綆斓囊蕾嚊_突問題,二方庫發(fā)布者應當遵循以下原則:精簡可控原則APIServiceAPIprovidedlog穩(wěn)定可追溯原則方便查到。除非用戶主動升級版本,否則公共二方庫的行為不應該發(fā)生變化。(三服務器TCPtime_wait超時時間。說明:240time_waittime_wait正例:linux/etc/sysctl.conf(

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論