熟读《阿里巴巴java开发手册》(六、工程结构,七、 设计规约,专有名词解释)
目錄
六、工程結(jié)構(gòu)
(一) 應(yīng)用分層
(二) 二方庫(kù)依賴
(三) 服務(wù)器
七、 設(shè)計(jì)規(guī)約
附 2: 專有名詞解釋
六、工程結(jié)構(gòu)
(一) 應(yīng)用分層
1. 【推薦】 圖中默認(rèn)上層依賴于下層,箭頭關(guān)系表示可直接依賴,如:開放接口層可以依賴于Web 層,也可以直接依賴于 Service 層,依此類推:
? 開放接口層:可直接封裝 Service 方法暴露成 RPC 接口;通過(guò) Web 封裝成 http 接口; 進(jìn)行網(wǎng)關(guān)安全控制、 流量控制等。
? 終端顯示層:各個(gè)端的模板渲染并執(zhí)行顯示的層。 當(dāng)前主要是 velocity 渲染, JS 渲染, JSP 渲染,移動(dòng)端展示等。
? Web 層:主要是對(duì)訪問(wèn)控制進(jìn)行轉(zhuǎn)發(fā),各類基本參數(shù)校驗(yàn),或者不復(fù)用的業(yè)務(wù)簡(jiǎn)單處理等。
? Service 層:相對(duì)具體的業(yè)務(wù)邏輯服務(wù)層。
? Manager 層:通用業(yè)務(wù)處理層,它有如下特征:
1) 對(duì)第三方平臺(tái)封裝的層,預(yù)處理返回結(jié)果及轉(zhuǎn)化異常信息。
2) 對(duì) Service 層通用能力的下沉,如緩存方案、 中間件通用處理。
3) 與 DAO 層交互,對(duì)多個(gè) DAO 的組合復(fù)用。
? DAO 層:數(shù)據(jù)訪問(wèn)層,與底層 MySQL、 Oracle、 Hbase 等進(jìn)行數(shù)據(jù)交互。
? 外部接口或第三方平臺(tái):包括其它部門 RPC 開放接口,基礎(chǔ)平臺(tái),其它公司的 HTTP 接口。
2. 【參考】 ( 分層異常處理規(guī)約) 在 DAO 層,產(chǎn)生的異常類型有很多,無(wú)法用細(xì)粒度的異常進(jìn)行 catch,使用 catch(Exception e)方式,并 throw new DAOException(e),不需要打印日志,因?yàn)槿罩驹?Manager/Service 層一定需要捕獲并打印到日志文件中去,如果同臺(tái)服務(wù)器再打日志,浪費(fèi)性能和存儲(chǔ)。在 Service 層出現(xiàn)異常時(shí),必須記錄出錯(cuò)日志到磁盤,盡可能帶上參數(shù)信息,相當(dāng)于保護(hù)案發(fā)現(xiàn)場(chǎng)。如果 Manager 層與 Service 同機(jī)部署,日志方式與 DAO 層處理一致,如果是單獨(dú)部署,則采用與 Service 一致的處理方式。 Web 層絕不應(yīng)該繼續(xù)往上拋異常,因?yàn)橐呀?jīng)處于頂層,如果意識(shí)到這個(gè)異常將導(dǎo)致頁(yè)面無(wú)法正常渲染,那么就應(yīng)該直接跳轉(zhuǎn)到友好錯(cuò)誤頁(yè)面, 加上用戶容易理解的錯(cuò)誤提示信息。開放接口層要將異常處理成錯(cuò)誤碼和錯(cuò)誤信息方式返回。
3. 【參考】 分層領(lǐng)域模型規(guī)約:
? DO( Data Object): 此對(duì)象與數(shù)據(jù)庫(kù)表結(jié)構(gòu)一一對(duì)應(yīng),通過(guò) DAO 層向上傳輸數(shù)據(jù)源對(duì)象。
? DTO( Data Transfer Object):數(shù)據(jù)傳輸對(duì)象, Service 或 Manager 向外傳輸?shù)膶?duì)象。
? BO( Business Object):業(yè)務(wù)對(duì)象, 由 Service 層輸出的封裝業(yè)務(wù)邏輯的對(duì)象。
? AO( Application Object): 應(yīng)用對(duì)象, 在 Web 層與 Service 層之間抽象的復(fù)用對(duì)象模型,極為貼近展示層,復(fù)用度不高。
? VO( View Object):顯示層對(duì)象,通常是 Web 向模板渲染引擎層傳輸?shù)膶?duì)象。
? Query:數(shù)據(jù)查詢對(duì)象,各層接收上層的查詢請(qǐng)求。 注意超過(guò) 2 個(gè)參數(shù)的查詢封裝,禁止使用 Map 類來(lái)傳輸。
(二) 二方庫(kù)依賴
1. 【強(qiáng)制】 定義 GAV 遵從以下規(guī)則:
1) GroupID 格式: com.{公司/BU }.業(yè)務(wù)線 [.子業(yè)務(wù)線],最多 4 級(jí)。
說(shuō)明: {公司/BU} 例如: alibaba/taobao/tmall/aliexpress 等 BU 一級(jí);子業(yè)務(wù)線可選。
正例: com.taobao.jstorm 或 com.alibaba.dubbo.register
2) ArtifactID 格式:產(chǎn)品線名-模塊名。語(yǔ)義不重復(fù)不遺漏,先到中央倉(cāng)庫(kù)去查證一下。
正例: dubbo-client / fastjson-api / jstorm-tool
3) Version:詳細(xì)規(guī)定參考下方。
2. 【強(qiáng)制】 二方庫(kù)版本號(hào)命名方式:主版本號(hào).次版本號(hào).修訂號(hào)
1) 主版本號(hào): 產(chǎn)品方向改變, 或者大規(guī)模 API 不兼容, 或者架構(gòu)不兼容升級(jí)。
2) 次版本號(hào): 保持相對(duì)兼容性,增加主要功能特性,影響范圍極小的 API 不兼容修改。
3) 修訂號(hào): 保持完全兼容性, 修復(fù) BUG、 新增次要功能特性等。
說(shuō)明: 注意起始版本號(hào)必須為: 1.0.0,而不是 0.0.1, 正式發(fā)布的類庫(kù)必須先去中央倉(cāng)庫(kù)進(jìn)行查證,使版本號(hào)有延續(xù)性, 正式版本號(hào)不允許覆蓋升級(jí)。如當(dāng)前版本: 1.3.3, 那么下一個(gè)合理的版本號(hào): 1.3.4 或1.4.0 或 2.0.0
3. 【強(qiáng)制】 線上應(yīng)用不要依賴 SNAPSHOT 版本( 安全包除外) 。
說(shuō)明: 不依賴 SNAPSHOT 版本是保證應(yīng)用發(fā)布的冪等性。另外,也可以加快編譯時(shí)的打包構(gòu)建。
4. 【強(qiáng)制】 二方庫(kù)的新增或升級(jí),保持除功能點(diǎn)之外的其它 jar 包仲裁結(jié)果不變。如果有改變,必須明確評(píng)估和驗(yàn)證。
說(shuō)明: 在升級(jí)時(shí),進(jìn)行 dependency:resolve 前后信息比對(duì),如果仲裁結(jié)果完全不一致,那么通過(guò)dependency:tree 命令,找出差異點(diǎn),進(jìn)行<exclude>排除 jar 包。
5. 【強(qiáng)制】 二方庫(kù)里可以定義枚舉類型,參數(shù)可以使用枚舉類型,但是接口返回值不允許使用枚舉類型或者包含枚舉類型的 POJO 對(duì)象。
6. 【強(qiáng)制】 依賴于一個(gè)二方庫(kù)群時(shí),必須定義一個(gè)統(tǒng)一的版本變量,避免版本號(hào)不一致。
說(shuō)明: 依賴 springframework-core,-context,-beans,它們都是同一個(gè)版本,可以定義一個(gè)變量來(lái)保存版本: ${spring.version},定義依賴的時(shí)候,引用該版本。
7. 【強(qiáng)制】 禁止在子項(xiàng)目的 pom 依賴中出現(xiàn)相同的 GroupId,相同的 ArtifactId,但是不同的Version。
說(shuō)明: 在本地調(diào)試時(shí)會(huì)使用各子項(xiàng)目指定的版本號(hào),但是合并成一個(gè) war,只能有一個(gè)版本號(hào)出現(xiàn)在最后的 lib 目錄中。 可能出現(xiàn)線下調(diào)試是正確的,發(fā)布到線上卻出故障的問(wèn)題。
8. 【推薦】 底層基礎(chǔ)技術(shù)框架、核心數(shù)據(jù)管理平臺(tái)、或近硬件端系統(tǒng)謹(jǐn)慎引入第三方實(shí)現(xiàn)。
9. 【推薦】 所有 pom 文件中的依賴聲明放在<dependencies>語(yǔ)句塊中,所有版本仲裁放在<dependencyManagement>語(yǔ)句塊中。
說(shuō)明: <dependencyManagement>里只是聲明版本,并不實(shí)現(xiàn)引入,因此子項(xiàng)目需要顯式的聲明依賴, version 和 scope 都讀取自父 pom。而<dependencies>所有聲明在主 pom 的<dependencies>里的依賴都會(huì)自動(dòng)引入,并默認(rèn)被所有的子項(xiàng)目繼承。
10.【推薦】 二方庫(kù)不要有配置項(xiàng),最低限度不要再增加配置項(xiàng)。
11.【參考】 為避免應(yīng)用二方庫(kù)的依賴沖突問(wèn)題,二方庫(kù)發(fā)布者應(yīng)當(dāng)遵循以下原則:
1) 精簡(jiǎn)可控原則。移除一切不必要的 API 和依賴,只包含 Service API、必要的領(lǐng)域模型對(duì)象、 Utils類、常量、枚舉等。如果依賴其它二方庫(kù),盡量是 provided 引入,讓二方庫(kù)使用者去依賴具體版本號(hào);無(wú) log 具體實(shí)現(xiàn),只依賴日志框架。
2) 穩(wěn)定可追溯原則。每個(gè)版本的變化應(yīng)該被記錄,二方庫(kù)由誰(shuí)維護(hù),源碼在哪里,都需要能方便查到。除非用戶主動(dòng)升級(jí)版本,否則公共二方庫(kù)的行為不應(yīng)該發(fā)生變化。
(三) 服務(wù)器
1. 【推薦】 高并發(fā)服務(wù)器建議調(diào)小 TCP 協(xié)議的 time_wait 超時(shí)時(shí)間。
說(shuō)明: 操作系統(tǒng)默認(rèn) 240 秒后,才會(huì)關(guān)閉處于 time_wait 狀態(tài)的連接,在高并發(fā)訪問(wèn)下,服務(wù)器端會(huì)因?yàn)樘幱?time_wait 的連接數(shù)太多,可能無(wú)法建立新的連接,所以需要在服務(wù)器上調(diào)小此等待值。
正例: 在 linux 服務(wù)器上請(qǐng)通過(guò)變更/etc/sysctl.conf 文件去修改該缺省值(秒):net.ipv4.tcp_fin_timeout = 30
2. 【推薦】 調(diào)大服務(wù)器所支持的最大文件句柄數(shù)( File Descriptor,簡(jiǎn)寫為 fd) 。
說(shuō)明: 主流操作系統(tǒng)的設(shè)計(jì)是將 TCP/UDP 連接采用與文件一樣的方式去管理,即一個(gè)連接對(duì)應(yīng)于一個(gè)fd。 主流的 linux 服務(wù)器默認(rèn)所支持最大 fd 數(shù)量為 1024,當(dāng)并發(fā)連接數(shù)很大時(shí)很容易因?yàn)?fd 不足而出現(xiàn)“open too many files” 錯(cuò)誤,導(dǎo)致新的連接無(wú)法建立。 建議將 linux 服務(wù)器所支持的最大句柄數(shù)調(diào)高數(shù)倍(與服務(wù)器的內(nèi)存數(shù)量相關(guān)) 。
3. 【推薦】 給 JVM 環(huán)境參數(shù)設(shè)置-XX:+HeapDumpOnOutOfMemoryError 參數(shù),讓 JVM 碰到OOM 場(chǎng)景時(shí)輸出 dump 信息。
說(shuō)明: OOM 的發(fā)生是有概率的,甚至相隔數(shù)月才出現(xiàn)一例,出錯(cuò)時(shí)的堆內(nèi)信息對(duì)解決問(wèn)題非常有幫助。
4. 【推薦】 在線上生產(chǎn)環(huán)境, JVM 的 Xms 和 Xmx 設(shè)置一樣大小的內(nèi)存容量, 避免在 GC 后調(diào)整堆大小帶來(lái)的壓力。
5. 【參考】 服務(wù)器內(nèi)部重定向使用 forward; 外部重定向地址使用 URL 拼裝工具類來(lái)生成, 否則會(huì)帶來(lái) URL 維護(hù)不一致的問(wèn)題和潛在的安全風(fēng)險(xiǎn)。
七、 設(shè)計(jì)規(guī)約
1. 【強(qiáng)制】 存儲(chǔ)方案和底層數(shù)據(jù)結(jié)構(gòu)的設(shè)計(jì)獲得評(píng)審一致通過(guò),并沉淀成為文檔。
說(shuō)明: 有缺陷的底層數(shù)據(jù)結(jié)構(gòu)容易導(dǎo)致系統(tǒng)風(fēng)險(xiǎn)上升,可擴(kuò)展性下降,重構(gòu)成本也會(huì)因歷史數(shù)據(jù)遷移和系統(tǒng)平滑過(guò)渡而陡然增加,所以,存儲(chǔ)方案和數(shù)據(jù)結(jié)構(gòu)需要認(rèn)真地進(jìn)行設(shè)計(jì)和評(píng)審,生產(chǎn)環(huán)境提交執(zhí)行后,需要進(jìn)行 double check。
正例: 評(píng)審內(nèi)容包括存儲(chǔ)介質(zhì)選型、表結(jié)構(gòu)設(shè)計(jì)能否滿足技術(shù)方案、存取性能和存儲(chǔ)空間能否滿足業(yè)務(wù)發(fā)展、表或字段之間的辯證關(guān)系、字段名稱、字段類型、索引等;數(shù)據(jù)結(jié)構(gòu)變更(如在原有表中新增字段)也需要進(jìn)行評(píng)審?fù)ㄟ^(guò)后上線。
2. 【強(qiáng)制】 在需求分析階段,如果與系統(tǒng)交互的 User 超過(guò)一類并且相關(guān)的 User Case 超過(guò) 5個(gè),使用用例圖來(lái)表達(dá)更加清晰的結(jié)構(gòu)化需求。
3. 【強(qiáng)制】 如果某個(gè)業(yè)務(wù)對(duì)象的狀態(tài)超過(guò) 3 個(gè),使用狀態(tài)圖來(lái)表達(dá)并且明確狀態(tài)變化的各個(gè)觸發(fā)條件。
說(shuō)明: 狀態(tài)圖的核心是對(duì)象狀態(tài),首先明確對(duì)象有多少種狀態(tài),然后明確兩兩狀態(tài)之間是否存在直接轉(zhuǎn)換關(guān)系,再明確觸發(fā)狀態(tài)轉(zhuǎn)換的條件是什么。
正例: 淘寶訂單狀態(tài)有已下單、待付款、已付款、待發(fā)貨、已發(fā)貨、已收貨等。比如已下單與已收貨這兩種狀態(tài)之間是不可能有直接轉(zhuǎn)換關(guān)系的。
4. 【強(qiáng)制】 如果系統(tǒng)中某個(gè)功能的調(diào)用鏈路上的涉及對(duì)象超過(guò) 3 個(gè),使用時(shí)序圖來(lái)表達(dá)并且明確各調(diào)用環(huán)節(jié)的輸入與輸出。
說(shuō)明: 時(shí)序圖反映了一系列對(duì)象間的交互與協(xié)作關(guān)系,清晰立體地反映系統(tǒng)的調(diào)用縱深鏈路。
5. 【強(qiáng)制】 如果系統(tǒng)中模型類超過(guò) 5 個(gè),并且存在復(fù)雜的依賴關(guān)系,使用類圖來(lái)表達(dá)并且明確類之間的關(guān)系。
說(shuō)明: 類圖像建筑領(lǐng)域的施工圖,如果搭平房,可能不需要,但如果建造螞蟻 Z 空間大樓,肯定需要詳細(xì)的施工圖。
6. 【強(qiáng)制】 如果系統(tǒng)中超過(guò) 2 個(gè)對(duì)象之間存在協(xié)作關(guān)系,并且需要表示復(fù)雜的處理流程,使用活動(dòng)圖來(lái)表示。
說(shuō)明: 活動(dòng)圖是流程圖的擴(kuò)展,增加了能夠體現(xiàn)協(xié)作關(guān)系的對(duì)象泳道,支持表示并發(fā)等。
7. 【推薦】 需求分析與系統(tǒng)設(shè)計(jì)在考慮主干功能的同時(shí),需要充分評(píng)估異常流程與業(yè)務(wù)邊界。
反例: 用戶在淘寶付款過(guò)程中,銀行扣款成功,發(fā)送給用戶扣款成功短信,但是支付寶入款時(shí)由于斷網(wǎng)演練產(chǎn)生異常,淘寶訂單頁(yè)面依然顯示未付款,導(dǎo)致用戶投訴。
8. 【推薦】 類在設(shè)計(jì)與實(shí)現(xiàn)時(shí)要符合單一原則。
說(shuō)明: 單一原則最易理解卻是最難實(shí)現(xiàn)的一條規(guī)則,隨著系統(tǒng)演進(jìn),很多時(shí)候,忘記了類設(shè)計(jì)的初衷。
9. 【推薦】 謹(jǐn)慎使用繼承的方式來(lái)進(jìn)行擴(kuò)展,優(yōu)先使用聚合/組合的方式來(lái)實(shí)現(xiàn)。
說(shuō)明: 不得已使用繼承的話,必須符合里氏代換原則,此原則說(shuō)父類能夠出現(xiàn)的地方子類一定能夠出現(xiàn),比如, “把錢交出來(lái)” ,錢的子類美元、歐元、人民幣等都可以出現(xiàn)。
10.【推薦】 系統(tǒng)設(shè)計(jì)時(shí),根據(jù)依賴倒置原則,盡量依賴抽象類與接口,有利于擴(kuò)展與維護(hù)。
說(shuō)明: 低層次模塊依賴于高層次模塊的抽象,方便系統(tǒng)間的解耦。
11.【推薦】 系統(tǒng)設(shè)計(jì)時(shí),注意對(duì)擴(kuò)展開放,對(duì)修改閉合。
說(shuō)明: 極端情況下,交付線上生產(chǎn)環(huán)境的代碼都是不可修改的,同一業(yè)務(wù)域內(nèi)的需求變化,通過(guò)模塊或類的擴(kuò)展來(lái)實(shí)現(xiàn)。
12.【推薦】 系統(tǒng)設(shè)計(jì)階段,共性業(yè)務(wù)或公共行為抽取出來(lái)公共模塊、公共配置、公共類、公共方法等, 避免出現(xiàn)重復(fù)代碼或重復(fù)配置的情況。
說(shuō)明: 隨著代碼的重復(fù)次數(shù)不斷增加,維護(hù)成本指數(shù)級(jí)上升。
13.【推薦】 避免如下誤解: 敏捷開發(fā) = 講故事 + 編碼 + 發(fā)布。
說(shuō)明: 敏捷開發(fā)是快速交付迭代可用的系統(tǒng),省略多余的設(shè)計(jì)方案,摒棄傳統(tǒng)的審批流程,但核心關(guān)鍵點(diǎn)上的必要設(shè)計(jì)和文檔沉淀是需要的。
反例: 某團(tuán)隊(duì)為了業(yè)務(wù)快速發(fā)展,敏捷成了產(chǎn)品經(jīng)理催進(jìn)度的借口, 系統(tǒng)中均是勉強(qiáng)能運(yùn)行但像面條一樣的代碼, 可維護(hù)性和可擴(kuò)展性極差,一年之后,不得不進(jìn)行大規(guī)模重構(gòu),得不償失。
14.【參考】 系統(tǒng)設(shè)計(jì)主要目的是明確需求、理順邏輯、后期維護(hù),次要目的用于指導(dǎo)編碼。
說(shuō)明: 避免為了設(shè)計(jì)而設(shè)計(jì),系統(tǒng)設(shè)計(jì)文檔有助于后期的系統(tǒng)維護(hù)和重構(gòu),所以設(shè)計(jì)結(jié)果需要進(jìn)行分類歸檔保存。
15.【參考】 設(shè)計(jì)的本質(zhì)就是識(shí)別和表達(dá)系統(tǒng)難點(diǎn), 找到系統(tǒng)的變化點(diǎn),并隔離變化點(diǎn)。
說(shuō)明: 世間眾多設(shè)計(jì)模式目的是相同的, 即隔離系統(tǒng)變化點(diǎn)。
16.【參考】 系統(tǒng)架構(gòu)設(shè)計(jì)的目的:
? 確定系統(tǒng)邊界。確定系統(tǒng)在技術(shù)層面上的做與不做。
? 確定系統(tǒng)內(nèi)模塊之間的關(guān)系。確定模塊之間的依賴關(guān)系及模塊的宏觀輸入與輸出。
? 確定指導(dǎo)后續(xù)設(shè)計(jì)與演化的原則。使后續(xù)的子系統(tǒng)或模塊設(shè)計(jì)在規(guī)定的框架內(nèi)繼續(xù)演化。
? 確定非功能性需求。非功能性需求是指安全性、可用性、可擴(kuò)展性等。
17.【參考】 在做無(wú)障礙產(chǎn)品設(shè)計(jì)時(shí),需要考慮到:
? 所有可交互的控件元素必須能被 tab 鍵聚焦,并且焦點(diǎn)順序需符合自然操作邏輯。
? 用于登陸校驗(yàn)和請(qǐng)求攔截的驗(yàn)證碼均需提供圖形驗(yàn)證以外的其它方式。
? 自定義的控件類型需明確交互方式。
?
附 2: 專有名詞解釋
1. POJO( Plain Ordinary Java Object) : 在本手冊(cè)中, POJO 專指只有 setter / getter /toString 的簡(jiǎn)單類,包括 DO/DTO/BO/VO 等。
2. GAV( GroupId、 ArtifactctId、 Version) : Maven 坐標(biāo),是用來(lái)唯一標(biāo)識(shí) jar 包。
3. OOP( Object Oriented Programming) : 本手冊(cè)泛指類、對(duì)象的編程處理方式。
4. ORM( Object Relation Mapping) : 對(duì)象關(guān)系映射,對(duì)象領(lǐng)域模型與底層數(shù)據(jù)之間的轉(zhuǎn)換,本文泛指 iBATIS, mybatis 等框架。
5. NPE( java.lang.NullPointerException) : 空指針異常。
6. SOA( Service-Oriented Architecture) : 面向服務(wù)架構(gòu),它可以根據(jù)需求通過(guò)網(wǎng)絡(luò)對(duì)松散耦合的粗粒度應(yīng)用組件進(jìn)行分布式部署、組合和使用, 有利于提升組件可重用性,可維護(hù)性。
7. IDE( Integrated Development Environment) : 用于提供程序開發(fā)環(huán)境的應(yīng)用程序,一般包括代碼編輯器、編譯器、調(diào)試器和圖形用戶界面等工具, 本《手冊(cè)》 泛指 IntelliJ IDEA 和eclipse。
8. OOM( Out Of Memory) : 源于 java.lang.OutOfMemoryError, 當(dāng) JVM 沒(méi)有足夠的內(nèi)存來(lái)為對(duì)象分配空間并且垃圾回收器也無(wú)法回收空間時(shí), 系統(tǒng)出現(xiàn)的嚴(yán)重狀況。
9. 一方庫(kù): 本工程內(nèi)部子項(xiàng)目模塊依賴的庫(kù)( jar 包) 。
10.二方庫(kù): 公司內(nèi)部發(fā)布到中央倉(cāng)庫(kù),可供公司內(nèi)部其它應(yīng)用依賴的庫(kù)( jar 包) 。
11.三方庫(kù): 公司之外的開源庫(kù)( jar 包) 。
?
?
總結(jié)
以上是生活随笔為你收集整理的熟读《阿里巴巴java开发手册》(六、工程结构,七、 设计规约,专有名词解释)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 熟读《阿里巴巴java开发手册》(五、
- 下一篇: mysql死锁场景汇总整理