Spring 中的注解與分層思想


在Spring框架中最常見的幾個(gè)注解

@Controller, @Service, @Component, @Repository

其中@Component是一種通用名稱,泛指任意可以通過Spring來管理的組件吼野,@Controller, @Service, @Repository則是一種特定的組件含末,通常用來表示某種特定場(chǎng)合下的組件嫡霞,比如@Repository用來表示倉庫(數(shù)據(jù)層族铆,DAO)叶堆,并且Spring 框架會(huì)根據(jù)這種應(yīng)用場(chǎng)景做些定制包斑,比如@Repository同時(shí)具備了自動(dòng)化的異常轉(zhuǎn)換。類似的渠欺, @Service則用來表示服務(wù)層相關(guān)的類妹蔽, @Controller則用來表示展示層(presentation)的類。

那Service是什么呢挠将?

Service 表示了在軟件分層設(shè)計(jì)中的Service層胳岂,用來連結(jié)數(shù)據(jù)層(DAO)和展示層(Presentation)。

為什么要在DAO層上加一層Service呢舔稀?

在某些簡(jiǎn)單的應(yīng)用中乳丰,DAO層的功能和Service的功能很接近,甚至初學(xué)者會(huì)覺得Service層做的事情和DAO層都一樣镶蹋,那為啥還要將Service層單獨(dú)拿出來做一遍呢?而且赏半,很多場(chǎng)景下贺归,Service層和DAO層同時(shí)存在,往往會(huì)增加代碼復(fù)雜度断箫,編碼工作量拂酣,寫的不好甚至?xí)斐苫煜?/p>

通常來說,DAO層應(yīng)盡力保持簡(jiǎn)單仲义,其功能僅僅是提供了數(shù)據(jù)庫的連接婶熬,以及最簡(jiǎn)單的增刪改查(Crud),有時(shí)還需要做些抽象埃撵,以此來連接使用不同技術(shù)的數(shù)據(jù)庫赵颅。除此之外,任何業(yè)務(wù)相關(guān)的操作都應(yīng)該放到Service層暂刘,即Service層用來編寫業(yè)務(wù)邏輯饺谬,即操作從DAO層讀取的數(shù)據(jù)谣拣,或者將處理好的數(shù)據(jù)給DAO層,當(dāng)使用Domain Driven Design時(shí)森缠, 這兩個(gè)類通常會(huì)放到同一個(gè)Domain(包)中,即便在簡(jiǎn)單的應(yīng)用中贵涵,他們的代碼可能極其類似列肢,但是仍應(yīng)該分別對(duì)待恰画。而不是跳過service層(service)直接去使用DAO層(repository)來放業(yè)務(wù)邏輯數(shù)據(jù)例书。

這樣帶來的好處帶來更好的模塊化結(jié)構(gòu),有便于后期的擴(kuò)展和維護(hù)决采,比如更換數(shù)據(jù)庫實(shí)現(xiàn)時(shí)自沧,我們僅僅需要處理DAO層的內(nèi)容就好了。并且树瞭,當(dāng)業(yè)務(wù)邏輯比較復(fù)雜的時(shí)候,比如有很多報(bào)告要出的時(shí)候晒喷,Service層就提供了一個(gè)很好的空間來實(shí)現(xiàn)這些代碼。

其次衣盾,在web應(yīng)用開發(fā)中爷抓,使用Service層可以將web類的活動(dòng)限制在controller中,這樣可以獨(dú)立的測(cè)試service層

另外蓝撇,還有一種情況,就是當(dāng)應(yīng)用極其復(fù)雜渤昌,需要同時(shí)使用多種數(shù)據(jù)庫時(shí),將從DAO中獲取數(shù)據(jù)的動(dòng)作放到一起可以減少數(shù)據(jù)庫的操作迈窟,并且可以保證數(shù)據(jù)的一致性忌栅。同時(shí)Service可以嵌套,因此如果需要使用不同的數(shù)據(jù)庫時(shí)狂秘,可以在service中指定。

在Service中也可以放一些通知類的操作破衔,比如發(fā)送郵件等钱烟,這樣也可以保持controller的整潔嫡丙。

還有一個(gè)潛在的好處是安全性读第,當(dāng)使用service層包裹DAO層后曙博,數(shù)據(jù)庫的鏈接是被service層保護(hù)起來的,這樣如果客戶端被某種情況攻陷父泳,其只能使用service層提供的有限數(shù)據(jù)吴汪,而無法直接攻擊數(shù)據(jù)庫

另外,在Spring 框架中漾橙,security也是在Service層實(shí)現(xiàn)的。根據(jù)上面的邏輯脾歇,我們?cè)趯?shí)際開發(fā)中淘捡,應(yīng)該不去實(shí)現(xiàn)自己的DAO層,而是使用Spring Data JPA案淋,因?yàn)镾pring Data JPA已經(jīng)實(shí)現(xiàn)了DAO層险绘。

這種寫法常見的問題有啥?

最常見的寫法(或者是錯(cuò)誤的寫法)有以下幾種

1瓣距、面向領(lǐng)域的模型對(duì)象僅僅用來存儲(chǔ)應(yīng)用中的數(shù)據(jù)代咸,換句話說,是不太符合domain model 設(shè)計(jì)的

2逻杖、處理模型數(shù)據(jù)的業(yè)務(wù)邏輯分散在service層

3思瘟、每個(gè)entity都有對(duì)應(yīng)的service類

這樣寫的原因很大程度來源于上面的分層理論,我們確實(shí)將應(yīng)用分成了展示層(web layer)滨攻,服務(wù)層(service layer)蓝翰,數(shù)據(jù)層(repository/dao)女嘲,但是實(shí)際后果卻是一個(gè)極其龐大的service層,這種寫法可以算是一個(gè)面向過程開發(fā)的代碼(procedural code)爆雹, 而不是面向?qū)ο箝_發(fā)媒至。好處是簡(jiǎn)單,當(dāng)業(yè)務(wù)不復(fù)雜時(shí)拒啰,確實(shí)沒有必要使用一個(gè)龐大的面向?qū)ο箝_發(fā)框架(domain driven design)。

一個(gè)責(zé)任并不明確的service層主要有以下問題

1剩失、業(yè)務(wù)邏輯分散在service層中册着,當(dāng)我們需要確認(rèn)或者檢查某個(gè)業(yè)務(wù)邏輯時(shí),可能要在多個(gè)service類中尋找演熟,也許并不那么容易司顿,另外如果同樣的業(yè)務(wù)邏輯在多個(gè)service類中用到時(shí),那么可能會(huì)存在大量的重復(fù)代碼大溜,這種重復(fù)代碼對(duì)于維護(hù)人員來說就是惡魔。

2座云、在service層中付材,每個(gè)entity都有對(duì)應(yīng)的service類時(shí),service層會(huì)有過多的依賴厌衔,甚至是循環(huán)依賴關(guān)系,而不是由松散耦合的service類構(gòu)成service層裸弦,理想中的service層應(yīng)該是由具有單一責(zé)任的service類構(gòu)成,并且這些service類具有松耦合關(guān)系理疙,如果不是這樣的service層,將難以理解砖顷,維護(hù)和重用赃梧。

主要的解決方法是

1、將與entity相關(guān)的業(yè)務(wù)邏輯統(tǒng)一放到領(lǐng)域模型對(duì)象相關(guān)的類中物咳,即所謂的domain service中蹄皱。這樣做的好處時(shí),傳統(tǒng)概念中的service層僅僅處理應(yīng)用相關(guān)的業(yè)務(wù)邏輯巷折,即作為Application Service。 然后domain service中處理domain 內(nèi)的業(yè)務(wù)邏輯油吭。業(yè)務(wù)邏輯將按照domain和application的方式分開署拟,容易定位和維護(hù)。傳統(tǒng)意義上的applicationservice層將變得整潔芍阎。

2缨恒、在domain service中我們將按照entity來編寫對(duì)應(yīng)的service轮听,這些都是特定的service,很小血巍,僅僅面對(duì)很專一的功能。舉例來說柿隙,如果應(yīng)用中的某個(gè)service提供person類的crud, 同時(shí)還提供用戶帳號(hào)的操作禀崖,那么我們應(yīng)該將person的crud單獨(dú)放到一個(gè)service中,然后將用戶帳號(hào)相關(guān)的操作放到另一個(gè)service中艺晴。

所有這些分層方式都是為了解決應(yīng)用從小項(xiàng)目成長(zhǎng)為大項(xiàng)目時(shí)可能遇到的隱患掸屡,代價(jià)是在項(xiàng)目還小時(shí),增加了項(xiàng)目的復(fù)雜度狈究,往往一句代碼就能搞定的事情盏求,卻要拆到三個(gè)類中去。但是太多的實(shí)際例子表明风喇,如果沒有好的架構(gòu),當(dāng)小項(xiàng)目膨脹到一定程度時(shí)还蹲,往往是無法維護(hù)的耙考,只能全部推倒重寫。

在Domain Driven Design中如何區(qū)分各種Service斗遏?

在DDD中鞋邑,service有三種類型

Domain Service

Domain Service: 用于放置領(lǐng)域?qū)ο笙嚓P(guān)的業(yè)務(wù)邏輯,這些業(yè)務(wù)邏輯通常并不適合放到entity中枚碗,也不是常見到的CRUD(這些應(yīng)該放到Repository), 將Domain Service 和Domain Objects放到一起是合理的遵堵,它們都是關(guān)注于domain相關(guān)的業(yè)務(wù)邏輯。在Domain Service中可以使用注入repository的方式來使用entity對(duì)應(yīng)的repository锡足。

舉一個(gè)例子:

一個(gè)圖書館有三個(gè)entity:Book壳坪, Client,Inventory弥虐, 當(dāng)把一本書借給一個(gè)客戶時(shí),就對(duì)應(yīng)了一個(gè)Domain Service珠插。在一個(gè)例子颖对,在Eric Evans的《Domain Driven Design》書中,轉(zhuǎn)賬服務(wù)(FundsTransferService)也是一種domain service顾患,它涉及到帳號(hào)BankAccount个唧,但是并不適合放到BankAccount中。

Application Service

Application Service: 用于為應(yīng)用外的client或consumer提供應(yīng)用級(jí)別的服務(wù)徙歼,比如一個(gè)外部客戶端(程序)需要使用某個(gè)entity的CRUD時(shí),這些服務(wù)程序放到Application Service桨螺。

Application Service通常會(huì)使用Domain Service和repository來處理外部的請(qǐng)求酿秸。常見的場(chǎng)景是,從repository中拿到一些domain objects辣苏, 然后執(zhí)行某些操作考润,在將其放回repository(或者不放)读处, Application Service對(duì)應(yīng)著大部分用戶使用場(chǎng)景,在寫一個(gè)應(yīng)用時(shí)罚舱,可以先從Application service寫起绎谦,這樣可以很好界定應(yīng)用的功能和范圍粥脚。repository雖然可以在某些場(chǎng)景下注入到domain service中,但是更常見的是注入到applicatinoservice中冤留。

Infrastructure service

還有一種Infrastructure service:用于抽象一些技術(shù)問題树灶,比如消息隊(duì)列,郵件服務(wù)

具體例子spring-petclinic

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市像寒,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌携悯,老刑警劉巖筷笨,帶你破解...
    沈念sama閱讀 221,198評(píng)論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異逊彭,居然都是意外死亡构订,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評(píng)論 3 398
  • 文/潘曉璐 我一進(jìn)店門囊榜,熙熙樓的掌柜王于貴愁眉苦臉地迎上來亥宿,“玉大人,你說我怎么就攤上這事烫扼。” “怎么了悟狱?”我有些...
    開封第一講書人閱讀 167,643評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵挤渐,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我浴麻,道長(zhǎng),這世上最難降的妖魔是什么椭赋? 我笑而不...
    開封第一講書人閱讀 59,495評(píng)論 1 296
  • 正文 為了忘掉前任或杠,我火速辦了婚禮悍赢,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挟鸠。我一直安慰自己,他們只是感情好艘希,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,502評(píng)論 6 397
  • 文/花漫 我一把揭開白布覆享。 她就那樣靜靜地躺著,像睡著了一般撒顿。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上吩屹,一...
    開封第一講書人閱讀 52,156評(píng)論 1 308
  • 那天拧抖,我揣著相機(jī)與錄音,去河邊找鬼擦盾。 笑死,一個(gè)胖子當(dāng)著我的面吹牛厌衙,可吹牛的內(nèi)容都是我干的绞绒。 我是一名探鬼主播蓬衡,決...
    沈念sama閱讀 40,743評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼狰晚!你這毒婦竟也來了筒饰?” 一聲冷哼從身側(cè)響起壁晒,我...
    開封第一講書人閱讀 39,659評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤秒咐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后攒钳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體雷滋,經(jīng)...
    沈念sama閱讀 46,200評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,282評(píng)論 3 340
  • 正文 我和宋清朗相戀三年焕檬,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了澳泵。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,424評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡爆侣,死狀恐怖幢妄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乎赴,我是刑警寧澤,帶...
    沈念sama閱讀 36,107評(píng)論 5 349
  • 正文 年R本政府宣布饿序,位于F島的核電站羹蚣,受9級(jí)特大地震影響原探,放射性物質(zhì)發(fā)生泄漏顽素。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,789評(píng)論 3 333
  • 文/蒙蒙 一型型、第九天 我趴在偏房一處隱蔽的房頂上張望全蝶。 院中可真熱鬧,春花似錦绷落、人聲如沸丈冬。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評(píng)論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蓄氧。三九已至,卻和暖如春喉童,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背堂氯。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評(píng)論 1 271
  • 我被黑心中介騙來泰國打工咽白, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人晶框。 一個(gè)月前我還...
    沈念sama閱讀 48,798評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像蹲蒲,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子缘薛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,435評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容