- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- Java從單體架構升級到微服務(wù)要注意的一些問(wèn)題
由于近年來(lái)的移動(dòng)端的發(fā)展和 2C模式 的紅利,一些在風(fēng)口的企業(yè)的業(yè)務(wù)得到爆發(fā)式增長(cháng)。從架構層面來(lái)說(shuō),業(yè)務(wù)驅動(dòng)技術(shù)的變革,所以微服務(wù)架構的概念得到很多企業(yè)的青睞,因為可以解決服務(wù)的大流量和高并發(fā)以及穩定性的要求。
但是任何架構設計不是一蹴而就的,不能從起步就開(kāi)始使用微服務(wù),一般都是先通過(guò)單體架構來(lái)快速實(shí)現需求和搶占市場(chǎng),然后再迭代式擴展。不能一口氣吃個(gè)胖子。
這幾年自己有經(jīng)歷從單體到微服務(wù)的架構演變,也有直接參與到已經(jīng)落地的微服務(wù)架構的項目中。見(jiàn)過(guò)好的架構設計,也見(jiàn)過(guò)一些孬的設計。好的架構設計,代碼結構優(yōu)雅,分層清晰,業(yè)務(wù)邊界劃分明朗,業(yè)務(wù)開(kāi)發(fā)人員職責清晰。不好的設計就會(huì )導致代碼混亂難以維護,對新需求無(wú)法快速應變,開(kāi)發(fā)人員容易在補丁上打補丁,最后造成積重難返不得不重構。
架構師需要從業(yè)務(wù)層面和未來(lái)業(yè)務(wù)發(fā)展有個(gè)全面的規劃,讓架構高可用,易擴展,靈活易使用,隱藏其復雜性。好的架構會(huì )讓下面的業(yè)務(wù)開(kāi)發(fā)人員按照既定的模式“傻瓜式”編程。
既然第一步是單體架構,那么好的單體架構設計,為我們后期的微服務(wù)拆分會(huì )有事半功倍的效果。避免重復勞動(dòng)和過(guò)多的重寫(xiě)。我們可以從這些方面進(jìn)行一些有效的設計。
如果對未來(lái)的架構有微服務(wù)的考慮,那么在單體架構的時(shí)候就需要理清業(yè)務(wù)邊界的問(wèn)題,常見(jiàn)的簡(jiǎn)單劃分就是以業(yè)務(wù)區分,例如:用戶(hù),商品,訂單,支付,權限等等,具體的拆分程度可根據自身業(yè)務(wù)量和需要做劃分。
當前流行的 DDD(領(lǐng)域驅動(dòng)設計)可以作為一個(gè)指導原則,但是 DDD 比較偏向于理論,需要執行人員有良好的專(zhuān)業(yè)能力才能實(shí)施的比較好。
業(yè)務(wù)區分好之后,就是項目代碼模塊的設計。在代碼層我們需要根據MVC的模式,建議的代碼設計層次如下:
├─demo-common │ │ demo-common.iml │ │ pom.xml │ │ │ └─src │ ├─main │ │ ├─java │ │ └─resources │ └─test │ └─java ├─demo-dao │ │ demo-dao.iml │ │ pom.xml │ │ │ └─src │ ├─main │ │ ├─java │ │ └─resources │ └─test │ └─java ├─demo-service │ │ demo-service.iml │ │ pom.xml │ │ │ └─src │ ├─main │ │ ├─java │ │ └─resources │ └─test │ └─java └─demo-web │ demo-web.iml │ pom.xml │ └─src ├─main │ ├─java │ └─resources └─test └─java
主要包含4個(gè) module 模塊
各模塊之間的依賴(lài)關(guān)系為:
項目 Module 模塊設計完成之后,每個(gè)模塊的內部 package 包如何設計呢?通常有兩種劃分模式:根據業(yè)務(wù)模塊然后內部按MVC劃分,根據MVC模式然后內部按業(yè)務(wù)劃分。
1、根據業(yè)務(wù)模塊劃分,就是將每個(gè)業(yè)務(wù)模塊作為一個(gè) package,然后每個(gè)package里面有自己的 MVC,這樣就做到業(yè)務(wù)模塊的隔離。
2、根據 MVC 模式劃分,先根據 MVC模式劃分不同的包,service,serviceImpl,dto等,然后再是各個(gè)業(yè)務(wù)自己的模型和服務(wù)接口。
針對上述的兩個(gè)劃分模式,個(gè)人的選擇是根據業(yè)務(wù)模式劃分,這樣的包設計與后期微服務(wù)拆分有良好的匹配度,拆分的時(shí)候只需要將每個(gè)業(yè)務(wù)包下的代碼 Copy 到新的微服務(wù)中就行了,易遷移變動(dòng)小。每個(gè)模塊中對不同的業(yè)務(wù)通過(guò) package 包名進(jìn)行劃分,例如:com.example.jajian.service.order、com.example.jajian.service.user等。
└─src ├─main │ ├─java │ │ └─com │ │ └─example │ │ └─jajian │ │ ├─common │ │ │ BaserService.java │ │ │ │ │ └─service │ │ ├─order │ │ │ ├─dto │ │ │ │ OrderDto.java │ │ │ │ │ │ │ └─service │ │ │ │ OrderService.java │ │ │ │ │ │ │ └─impl │ │ │ OrderServiceImpl.java │ │ │ │ │ ├─pay │ │ │ ├─dto │ │ │ │ PayDto.java │ │ │ │ │ │ │ └─service │ │ │ │ PayService.java │ │ │ │ │ │ │ └─impl │ │ │ PayServiceImpl.java │ │ │ │ │ └─user │ │ ├─dto │ │ │ UserDto.java │ │ │ │ │ └─service │ │ │ UserService.java │ │ │ │ │ └─impl │ │ UserServiceImpl.java │ │ │ └─resources └─test └─java
這樣劃分有什么好處?我們單體架構的時(shí)候這樣開(kāi)發(fā),當需要拆分成微服務(wù)的時(shí)候就可以直接將業(yè)務(wù)包拆分出去,因為每個(gè)業(yè)務(wù)包里面就已經(jīng)包含了所有的當前業(yè)務(wù)的關(guān)聯(lián)業(yè)務(wù)類(lèi)。
單表關(guān)聯(lián)由于業(yè)務(wù)需要而且簡(jiǎn)單方便易使用,所以多表關(guān)聯(lián)查詢(xún)在單體服務(wù)中是普遍存在的,如果我們后期不需要做服務(wù)拆分則可以不需要考慮這方面的限制。
但是如果后期有微服務(wù)的規劃,那么單體服務(wù)的時(shí)候如果沒(méi)有做這個(gè)方面的限制,mybatis 的 mapper.xml中有過(guò)多的多表關(guān)聯(lián)查詢(xún),這些關(guān)聯(lián)查詢(xún)會(huì )嚴重影響服務(wù)拆分的進(jìn)度和復雜度。
如果同屬于一個(gè)業(yè)務(wù)領(lǐng)域則可以使用關(guān)聯(lián)查詢(xún),而那些微服務(wù)拆分后屬于不同領(lǐng)域的業(yè)務(wù)則應避免使用多表關(guān)聯(lián)查詢(xún),因為不同的業(yè)務(wù)領(lǐng)域后期會(huì )被隔離拆分到不同的服務(wù)當中,即數據庫表都是分布在不同的服務(wù)器上,所有服務(wù)之間都是通過(guò)RPC方式進(jìn)行通信,關(guān)聯(lián)查詢(xún)這時(shí)是無(wú)法處理的。
??吹胶芏?coder 會(huì )在Controller 層做一些業(yè)務(wù)處理,個(gè)人認為這是很不規范的。Controller層是控制層,是和前端進(jìn)行數據轉換的,這里我們應該只做請求的接受和返回,也無(wú)需做一些異常的try...catch...的捕獲,異??梢酝ㄟ^(guò)全局通用攔截器統一進(jìn)行攔截然后返回給前端異常提示語(yǔ),提升代碼的簡(jiǎn)潔性。
所有的參數校驗也放到 service層,因為如果服務(wù)內部調用也可以使用提高代碼的共用度。當然分層領(lǐng)域模型最好也能區分開(kāi),
這樣區分開(kāi)的好處是,當你需要對展示層數據進(jìn)行特殊定制化的時(shí)候可以靈活變通,例如針對用戶(hù)隱私信息身份證號,手機號碼脫敏處理,或者用戶(hù)ID加密顯示等。
最后就是統一通用返回類(lèi)了,通過(guò)這種格式的封裝我們將數據格式進(jìn)行全局格式化,這里的狀態(tài)碼可以自己設計的更詳細一點(diǎn)。
public class CommonResult<T> { public static final String CODE_SUCCESS = "0"; public static final String CODE_FAILED = "9999"; private String code; private T data; private String msg; private CommonResult(String code, T data, String msg) { this.code = code; this.data = data; this.msg = msg; } public boolean isSuccess() { return CODE_SUCCESS.equals(code); } public static <T> CommonResult<T> success() { return new CommonResult<>(CODE_SUCCESS, null, null); } public static <T> CommonResult<T> success(T data) { return new CommonResult<>(CODE_SUCCESS, data, null); } public static <T> CommonResult<T> success(T data, String msg) { return new CommonResult<>(CODE_SUCCESS, data, msg); } public static <T> CommonResult<T> failed() { return new CommonResult<>(CODE_FAILED, null, null); } public static <T> CommonResult<T> failed(String errorCode, String msg) { return new CommonResult<>(errorCode, null, msg); } public static <T> CommonResult<T> failed(String msg) { return new CommonResult<>(CODE_FAILED, null, msg); } public static <T> CommonResult<T> failed(T data, String msg) { return new CommonResult<>(CODE_FAILED, data, msg); } public static <T> CommonResult<T> failed(String errorCode, T data, String msg) { return new CommonResult<>(errorCode, data, msg); } // 省略 setter、getter }
以上只是列舉了單體服務(wù)未來(lái)規劃做微服務(wù)時(shí)需要注意的一部分簡(jiǎn)單內容,每個(gè)人在做單體架構拆分成微服務(wù)的時(shí)候都會(huì )踩到各種各樣的坑,這些坑成了我們的開(kāi)發(fā)經(jīng)驗,有了這些坑就會(huì )形成注意點(diǎn),在我們下次開(kāi)發(fā)時(shí)就會(huì )具有指導意義。也許我們程序員就是在踩坑和填坑的過(guò)程中成長(cháng)壯大起來(lái)的。
以上就是Java從單體架構升級到微服務(wù)要注意的一些問(wèn)題的詳細內容,更多關(guān)于Java的資料請關(guān)注腳本之家其它相關(guān)文章!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站