乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      那些年,我們見過的Java服務(wù)端亂象

       一守望先鋒一 2019-08-06

      查爾斯·狄更斯在《雙城記》中寫道:“這是一個最好的時代,也是一個最壞的時代?!币苿踊ヂ?lián)網(wǎng)的快速發(fā)展,出現(xiàn)了許多新機遇,很多創(chuàng)業(yè)者伺機而動;隨著行業(yè)競爭加劇,互聯(lián)網(wǎng)紅利逐漸消失,很多創(chuàng)業(yè)公司九死一生。

      筆者在初創(chuàng)公司摸爬滾打數(shù)年,接觸了各式各樣的Java微服務(wù)架構(gòu),從中獲得了一些優(yōu)秀的理念,但也發(fā)現(xiàn)了一些不合理的現(xiàn)象?,F(xiàn)在,筆者總結(jié)了一些創(chuàng)業(yè)公司存在的Java服務(wù)端亂象,并嘗試性地給出了一些不成熟的建議。

      1.使用Controller基類和Service基類

      1.1.現(xiàn)象描述

      1.1.1.Controller基類

      常見的Controller基類如下:

      常見的Controller基類主要包含注入服務(wù)、靜態(tài)常量和靜態(tài)函數(shù)等,便于所有的Controller繼承它,并在函數(shù)中可以直接使用這些資源。

      1.1.2.Service基類

      常見的Service基類如下:

      常見的Service基類主要包括注入DAO、注入服務(wù)、注入?yún)?shù)、靜態(tài)常量、服務(wù)函數(shù)、靜態(tài)函數(shù)等,便于所有的Service繼承它,并在函數(shù)中可以直接使用這些資源。

      1.2.論證基類必要性

      首先,了解一下里氏替換原則:

      里氏代換原則(Liskov Substitution Principle,簡稱LSP):所有引用基類(父類)的地方必須能透明地使用其子類的對象。

      其次,了解一下基類的優(yōu)點:

      1. 子類擁有父類的所有方法和屬性,從而減少了創(chuàng)建子類的工作量;

      2. 提高了代碼的重用性,子類擁有父類的所有功能;

      3. 提高了代碼的擴展性,子類可以添加自己的功能。

      所以,我們可以得出以下結(jié)論:

      1. Controller基類和Service基類在整個項目中并沒有直接被使用,也就沒有可使用其子類替換基類的場景,所以不滿足里氏替換原則;

      2. Controller基類和Service基類并沒有抽象接口函數(shù)或虛函數(shù),即所有繼承基類的子類間沒有相關(guān)共性,直接導(dǎo)致在項目中仍然使用的是子類;

      3. Controller基類和Service基類只關(guān)注了重用性,即子類能夠輕松使用基類的注入DAO、注入服務(wù)、注入?yún)?shù)、靜態(tài)常量、服務(wù)函數(shù)、靜態(tài)函數(shù)等資源。但是,忽略了這些資源的必要性,即這些資源并不是子類所必須的,反而給子類帶來了加載時的性能損耗。

      綜上所述,Controller基類和Service基類只是一個雜湊類,并不是一個真正意義上的基類,需要進(jìn)行拆分。

      1.3.拆分基類的方法

      由于Service基類比Controller基類更典型,本文以Service基類舉例說明如何來拆分“基類”。

      1.3.1.把注入實例放入實現(xiàn)類

      根據(jù)“使用即引入、無用則刪除”原則,在需要使用的實現(xiàn)類中注入需要使用的DAO、服務(wù)和參數(shù)。

      1.3.2.把靜態(tài)常量放入常量類

      對于靜態(tài)常量,可以把它們封裝到對應(yīng)的常量類中,在需要時直接使用即可。

      1.3.3.把服務(wù)函數(shù)放入服務(wù)類

      對于服務(wù)函數(shù),可以把它們封裝到對應(yīng)的服務(wù)類中。在別的服務(wù)類使用時,可以注入該服務(wù)類實例,然后通過實例調(diào)用服務(wù)函數(shù)。

      1.3.4.把靜態(tài)函數(shù)放入工具類

      對于靜態(tài)函數(shù),可以把它們封裝到對應(yīng)的工具類中,在需要時直接使用即可。

      2.把業(yè)務(wù)代碼寫在Controller中

      2.1.現(xiàn)象描述

      我們會經(jīng)常會在Controller類中看到這樣的代碼:

      編寫人員給出的理由是:一個簡單的接口函數(shù),這么寫也能滿足需求,沒有必要去封裝成一個服務(wù)函數(shù)。

      2.2.一個特殊的案例

      案例代碼如下:

      訪問結(jié)果如下:

      curl http://localhost:8080/test/access
      系統(tǒng)(null)歡迎您訪問!

      為什么參數(shù)systemName(系統(tǒng)名稱)沒有被注入值?《Spring Documentation》給出的解釋是:

      Note that actual processing of the @Value annotation is performed by a BeanPostProcessor.

      BeanPostProcessor interfaces are scoped per-container. This is only relevant if you are using container hierarchies. If you define a BeanPostProcessor in one container, it will only do its work on the beans in that container. Beans that are defined in one container are not post-processed by a BeanPostProcessor in another container, even if both containers are part of the same hierarchy.

      意思是說:@Value是通過BeanPostProcessor來處理的,而WebApplicationContex和ApplicationContext是單獨處理的,所以WebApplicationContex不能使用父容器的屬性值。

      所以,Controller不滿足Service的需求,不要把業(yè)務(wù)代碼寫在Controller類中。

      2.3.服務(wù)端三層架構(gòu)

      SpringMVC服務(wù)端采用經(jīng)典的三層架構(gòu),即表現(xiàn)層、業(yè)務(wù)層、持久層,分別采用@Controller、@Service、@Repository進(jìn)行類注解。

      表現(xiàn)層(Presentation):又稱控制層(Controller),負(fù)責(zé)接收客戶端請求,并向客戶端響應(yīng)結(jié)果,通常采用HTTP協(xié)議。

      業(yè)務(wù)層(Business):又稱服務(wù)層(Service),負(fù)責(zé)業(yè)務(wù)相關(guān)邏輯處理,按照功能分為服務(wù)、作業(yè)等。

      持久層(Persistence):又稱倉庫層(Repository),負(fù)責(zé)數(shù)據(jù)的持久化,用于業(yè)務(wù)層訪問緩存和數(shù)據(jù)庫。

      所以,把業(yè)務(wù)代碼寫入到Controller類中,是不符合SpringMVC服務(wù)端三層架構(gòu)規(guī)范的。

      3.把持久層代碼寫在Service中

      把持久層代碼寫在Service中,從功能上來看并沒有什么問題,這也是很多人欣然接受的原因。

      3.1.引起以下主要問題

      1. 業(yè)務(wù)層和持久層混雜在一起,不符合SpringMVC服務(wù)端三層架構(gòu)規(guī)范;

      2. 在業(yè)務(wù)邏輯中組裝語句、主鍵等,增加了業(yè)務(wù)邏輯的復(fù)雜度;

      3. 在業(yè)務(wù)邏輯中直接使用第三方中間件,不便于第三方持久化中間件的替換;

      4. 同一對象的持久層代碼分散在各個業(yè)務(wù)邏輯中,背離了面對對象的編程思想;

      5. 在寫單元測試用例時,無法對持久層接口函數(shù)直接測試。

      3.2.把數(shù)據(jù)庫代碼寫在Service中

      這里以數(shù)據(jù)庫持久化中間件Hibernate的直接查詢?yōu)槔?/p>

      現(xiàn)象描述:

      建議方案:

      關(guān)于插件:

      阿里的AliGenerator是一款基于MyBatis Generator改造的DAO層代碼自動生成工具。利用AliGenerator生成的代碼,在執(zhí)行復(fù)雜查詢的時候,需要在業(yè)務(wù)代碼中組裝查詢條件,使業(yè)務(wù)代碼顯得特別臃腫。

      個人不喜歡用DAO層代碼生成插件,更喜歡用原汁原味的MyBatis XML映射,主要原因如下:

      • 會在項目中導(dǎo)入一些不符合規(guī)范的代碼;

      • 只需要進(jìn)行一個簡單查詢,也需要導(dǎo)入一整套復(fù)雜代碼;

      • 進(jìn)行復(fù)雜查詢時,拼裝條件的代碼復(fù)雜且不直觀,不如在XML中直接編寫SQL語句;

      • 變更表格后需要重新生成代碼并進(jìn)行覆蓋,可能會不小心刪除自定義函數(shù)。

      當(dāng)然,既然選擇了使用DAO層代碼生成插件,在享受便利的同時也應(yīng)該接受插件的缺點。

      3.3.把Redis代碼寫在Service中

      現(xiàn)象描述:

      建議方案:

      把一個Redis對象相關(guān)操作接口封裝為一個DAO類,符合面對對象的編程思想,也符合SpringMVC服務(wù)端三層架構(gòu)規(guī)范,更便于代碼的管理和維護(hù)。

      4.把數(shù)據(jù)庫模型類暴露給接口

      4.1.現(xiàn)象描述

      上面的代碼,看上去是滿足SpringMVC服務(wù)端三層架構(gòu)的,唯一的問題就是把數(shù)據(jù)庫模型類UserDO直接暴露給了外部接口。

      4.2.存在問題及解決方案

      存在問題:

      1. 間接暴露數(shù)據(jù)庫表格設(shè)計,給競爭對手競品分析帶來方便;

      2. 如果數(shù)據(jù)庫查詢不做字段限制,會導(dǎo)致接口數(shù)據(jù)龐大,浪費用戶的寶貴流量;

      3. 如果數(shù)據(jù)庫查詢不做字段限制,容易把敏感字段暴露給接口,導(dǎo)致出現(xiàn)數(shù)據(jù)的安全問題;

      4. 如果數(shù)據(jù)庫模型類不能滿足接口需求,需要在數(shù)據(jù)庫模型類中添加別的字段,導(dǎo)致數(shù)據(jù)庫模型類跟數(shù)據(jù)庫字段不匹配問題;

      5. 如果沒有維護(hù)好接口文檔,通過閱讀代碼是無法分辨出數(shù)據(jù)庫模型類中哪些字段是接口使用的,導(dǎo)致代碼的可維護(hù)性變差。

      解決方案:

      1. 從管理制度上要求數(shù)據(jù)庫和接口的模型類完全獨立;

      2. 從項目結(jié)構(gòu)上限制開發(fā)人員把數(shù)據(jù)庫模型類暴露給接口。

      4.3.項目搭建的三種方式

      下面,將介紹如何更科學(xué)地搭建Java項目,有效地限制開發(fā)人員把數(shù)據(jù)庫模型類暴露給接口。

      第1種:共用模型的項目搭建

      共用模型的項目搭建,把所有模型類放在一個模型項目(example-model)中,其它項目(example-repository、example-service、example-website)都依賴該模型項目,關(guān)系圖如下:

      序號項目名稱打包類型項目功能
      1example-modeljar定義了所有模型類,包括DO類和VO類等
      2example-repositoryjar對應(yīng)持久層,實現(xiàn)了MySQL、Redis相關(guān)DAO等
      3example-servicejar對應(yīng)業(yè)務(wù)層,實現(xiàn)了Service、Job、Workflow等
      4example-webappwar對應(yīng)表現(xiàn)層,實現(xiàn)了Controller、Interceptor、Filter等

      風(fēng)險:

      表現(xiàn)層項目(example-webapp)可以調(diào)用業(yè)務(wù)層項目(example-service)中的任意服務(wù)函數(shù),甚至于越過業(yè)務(wù)層直接調(diào)用持久層項目(example-repository)的DAO函數(shù)。

      第2種:模型分離的項目搭建

      模型分離的項目搭建,單獨搭建API項目(example-api),抽象出對外接口及其模型VO類。業(yè)務(wù)層項目(example-service)實現(xiàn)了這些接口,并向表現(xiàn)層項目(example-webapp)提供服務(wù)。表現(xiàn)層項目(example-webapp)只調(diào)用API項目(example-api)定義的服務(wù)接口。

      序號項目名稱打包類型項目功能
      1example-apijar業(yè)務(wù)層的表現(xiàn)層,定義了對外開放接口和VO類
      2example-repositoryjar對應(yīng)持久層,定義了DO類并實現(xiàn)了MySQL、Redis相關(guān)DAO等
      3example-servicejar對應(yīng)業(yè)務(wù)層,實現(xiàn)了Service、Job、Workflow等
      4example-webappwar對應(yīng)表現(xiàn)層,實現(xiàn)了Controller、Interceptor、Filter等

      風(fēng)險:

      表現(xiàn)層項目(example-webapp)仍然可以調(diào)用業(yè)務(wù)層項目(example-service)提供的內(nèi)部服務(wù)函數(shù)和持久層項目(example-repository)的DAO函數(shù)。為了避免這種情況,只好管理制度上要求表現(xiàn)層項目(example-webapp)只能調(diào)用API項目(example-api)定義的服務(wù)接口函數(shù)。

      第3種:服務(wù)化的項目搭建

      服務(wù)化的項目搭,就是把業(yè)務(wù)層項目(example-service)和持久層項目(example-repository)通過Dubbo項目(example-dubbo)打包成一個服務(wù),向業(yè)務(wù)層項目(example-webapp)或其它業(yè)務(wù)項目(other-service)提供API項目(example-api)中定義的接口函數(shù)。

      序號項目名稱打包類型項目功能
      1example-apijar對應(yīng)業(yè)務(wù)層的表現(xiàn)層,定義了對外開放接口和VO類
      2example-repositoryjar對應(yīng)持久層,定義了DO類并實現(xiàn)了MySQL、Redis相關(guān)DAO等
      3example-servicejar對應(yīng)業(yè)務(wù)層,實現(xiàn)了Service、Job、Workflow等
      4example-dubbowar對應(yīng)業(yè)務(wù)層的表現(xiàn)層,通過Dubbo提供服務(wù)
      5example-webappwar對應(yīng)表現(xiàn)層,實現(xiàn)了Controller等,通過Dubbo調(diào)用服務(wù)
      6other-servicejar對應(yīng)其它項目的業(yè)務(wù)層,通過Dubbo調(diào)用服務(wù)

      說明:Dubbo項目(example-dubbo)只發(fā)布API項目(example-api)中定義的服務(wù)接口,保證了數(shù)據(jù)庫模型無法暴露。業(yè)務(wù)層項目(example-webapp)或其它業(yè)務(wù)項目(other-service)只依賴了API項目(example-api),只能調(diào)用該項目中定義的服務(wù)接口。

      4.4.一條不太建議的建議

      有人會問:接口模型和持久層模型分離,接口定義了一個查詢數(shù)據(jù)模型VO類,持久層也需要定義一個查詢數(shù)據(jù)模型DO類;接口定義了一個返回數(shù)據(jù)模型VO類,持久層也需要定義一個返回數(shù)據(jù)模型DO類……這樣,對于項目早期快速迭代開發(fā)非常不利。能不能只讓接口不暴露持久層數(shù)據(jù)模型,而能夠讓持久層使用接口的數(shù)據(jù)模型?

      如果從SpringMVC服務(wù)端三層架構(gòu)來說,這是不允許的,因為它會影響三層架構(gòu)的獨立性。但是,如果從快速迭代開發(fā)來說,這是允許的,因為它并不會暴露數(shù)據(jù)庫模型類。所以,這是一條不太建議的建議。

      后記

      “仁者見仁、智者見智”,每個人都有自己的想法,而文章的內(nèi)容也只是我的一家之言。

      謹(jǐn)以此文獻(xiàn)給那些我工作過的創(chuàng)業(yè)公司,是您們曾經(jīng)放手讓我去整改亂象,讓我從中受益頗深并得以技術(shù)成長。

      作者:中間件小哥

        本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多