Spring Cloud工程模塊劃分

Spring Cloud工程模塊劃分


現在網絡上都在講Spring Cloud的各個組件,但當我們自己也把Spring Cloud引入進來的時候,卻發現第一個要解決的問題是:

工程的模塊如何劃分

在之前我寫過一篇重構購物車的過程的文章,下面就以這個購物車工程,來說明當時我是如何思考和如何做的。


工程要分幾個模塊


API模塊


當時的購物車工程是基於Spring Cloud搭建的,並對外暴露Resful接口。那麼第一個要思考的問題是,調用方如何使用購物車的微服務接口呢。有一種方式是由服務提供方生成一個SDK包,調用方引入SDK直接使用。這種方式目前應該是主流的做法,我個人也比較推崇這種方式。

因此,在工程裏,我們應該有個API工程,這個工程定義了所有的微服務接口,然後可以使用一些構建工具,生成一個SDK包。

shopcart-api

這個API工程只有兩樣東西,一個是微服務接口,另外一個是DTO對象。可以用package來區分。

shopcart-api
     api  //包名
     dto  //包名

API包裏可以用interface定義出所有的微服務接口。

public interface ShopCartApi {
    @RequestMapping(value = "/addToCart", method = RequestMethod.POST)
    ResponseDTO addToCart(@RequestBody(required = false) AddToCartDTO request) throws Exception;

    //其他接口
}

至於DTO,是用於網絡傳輸的對象。當我們想提供微服務接口的時候,首先要考慮的就是入參和出參。一般來說可以用DTO來表示的,所有DTO對象都必須以DTO結尾。這些DTO會以SDK包的形式,被調用方使用,調用方也必須將自己的業務數據封裝成DTO入參,然後才能調用後端的微服務接口。

後面我們只需要使用Maven或者Gradle,構建一個SDK包出來即可。如果是使用Maven,那麼組合使用

mvn clean install
mvn clean deploy

就可以生成SDK包,並且上傳到公司的Maven私服上了。


server工程


server工程用於存放controller的,是實際對外的resful微服務接口。

shopcart-server

server工程必須依賴api工程,並去實現API工程定義的微服務接口。

@RestController
public class ShopCartController implements ShopCartApi {
    @Override
    public ResponseDTO addSkuToShopCart(@RequestBody AddToCartDTO request) throws Exception {
        return null;
    }
}

這裏的ShopCartApi就是之前在API工程裏面定義的interface。那麼server工程裏的微服務接口可以直接去實現複雜的業務邏輯嗎?還是說再抽取一個模塊出來,專門用於實現業務邏輯呢?有一些公司,直接就在server工程裏實現複雜的業務邏輯,然後用一個service包,將業務邏輯servce類放入進去。理由是,再抽取一個service模塊用處不大呀,又無需用它來單獨build一個包,供外部使用。其實這樣做也沒啥問題,但是通常來說,業務邏輯實現類,最好還是單獨抽取成一個模塊,除了層次清晰一些之外,業務邏輯實現類還有另外一些職責,就是【穩定】【靈活】【通用】【易於測試】,是需要精心設計的,建議別跟controller混在一個模塊裏。

隨着業務不斷的增多,server工程裏的controller接口會不斷的增多和變化,但是經過精心設計的業務邏輯層,卻未必。


service工程


shopcart-service

如上所說,建議再建立一個service工程,將核心的業務邏輯封裝起來。service層對外暴露的對象是業務對象,統一以BO結尾。這裏就會有個問題,server工程調用完service層的接口,獲取到BO對象後,需要轉換成DTO對象。不過現在已經有非常成熟性能又好的映射工具了。orika就是其中的佼佼者。


模塊之間的依賴


server工程依賴api工程和service工程。


需要再搞個domain模塊嗎


我理解的domain也屬於業務邏輯的一部分,我個人是不太喜歡再搞個domain模塊的,直接將domain放置在service模塊裏即可。


客戶端如何調用服務端


在Spring Cloud裏,可以藉助feign

@FeignClient(value = "xxxxx",path = "/yyyyy")
public interface ShopCartClient extends ShopCartApi {

}

這裏的ShopCartApi就是購物車工程中api模塊的接口類。想要調用購物車的接口,直接使用ShopCartClient類即可。


進一步的思考


  • 如果是使用Spring Cloud來提供微服務的話,由於是Resful協議的,那麼調用方也可以不用SDK的方式來調用服務方接口,直接用RestTemplate調用即可,客戶端的接入成本很低,也不用擔心SDK的接口版本問題。

  • 使用SDK來調用服務端接口的方式,使用起來確實比較方便,不看接口文檔都可以直接編程了。但是要小心服務端接口的版本問題。

  • 聽網友說feign不靈活,目前就我自己的使用情況看,還好,歡迎網友在本文評論中說出自己的看法。

  • 部分網友也提出,微服務工程本來就很細粒度了,無需在微服務工程裏再分模塊了,不然會增加複雜度,我覺得有一定的道理,但是目前我還是傾向於分模塊哈。。


使用領域驅動設計來劃分模塊


也有些公司,使用領域驅動設計來劃分模塊,這塊我目前還不太熟悉,不過看起來挺高大上的,也希望網友在文章的評論裏,多多發表意見。

寫一篇文章不容易哈,覺得文章寫的還行,請在文章上方左側的位置點一下贊哈,萬分感謝。如下圖:
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章