ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
Github:https://github.com/Jimmey-Jiang/ABP-ASP.NET-Boilerplate-Project-CMS
前往博客園總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
在ABP框架中,倉(cāng)儲(chǔ),服務(wù),這塊算是最為重要一塊之一了.ABP框架提供了創(chuàng)建和組裝模塊的基礎(chǔ)囚霸,一個(gè)模塊能夠依賴于另一個(gè)模塊,一個(gè)程序集可看成一個(gè)模塊,
一個(gè)模塊可以通過一個(gè)類來定義這個(gè)模塊腰根,而給定義這個(gè)類要繼承自已經(jīng)瘋轉(zhuǎn)好的AbpModule..net通過反射來獲取這些程序集中的類或者方法
模塊的調(diào)用往往涉及到先后順序,如果模塊A依賴于模塊B,那么模塊B要在模塊A之前初始化,初始化就相當(dāng)于注冊(cè),如使用IocManager
對(duì)登記類進(jìn)行注冊(cè),
上面這個(gè)方法我們就把MyModule1 注入到MyModule2中了,在調(diào)用MyModule2的時(shí)候可以初始化MyModule1 .
什么是依賴注入呢?百科是這樣說:“依賴注入是一種軟件設(shè)計(jì)模式,一個(gè)或多個(gè)依賴項(xiàng)(或服務(wù))被注入或通過引用傳遞到一個(gè)依賴對(duì)象拓型,并且成為客戶端狀態(tài)的一部分。這種模式把客戶端依賴項(xiàng)的創(chuàng)建從它自己的行為中分離出來,允許程序設(shè)計(jì)成松耦合的靠闭,遵循依賴倒置和單一職責(zé)的原則点弯。和服務(wù)定位器模式相比捡絮,它允許客戶端知道他們使用的系統(tǒng)查找依賴項(xiàng)。”
不使用依賴注入技術(shù),很難管理依賴項(xiàng)和發(fā)布一個(gè)結(jié)構(gòu)良好的應(yīng)用。
假設(shè)我們有一個(gè)應(yīng)用程序服務(wù),使用倉(cāng)儲(chǔ)(
repository
)類插入實(shí)體到數(shù)據(jù)庫(kù)。在這種情況下,應(yīng)用程序服務(wù)類依賴于倉(cāng)儲(chǔ)(repository
)類,如下UserService
使用UserRepository
插入Person到數(shù)據(jù)庫(kù)阅羹。但是這段代碼有一些問題:
- 服務(wù)層
UserService
通過接口IUserRepository
調(diào)用CreatePerson
實(shí)現(xiàn)新增一個(gè)User對(duì)象,看似調(diào)用了IUserRepository
接口,但是實(shí)際上還是依賴于倉(cāng)促層的UserRepository
. -
UserService
通過IUserRepository
創(chuàng)建對(duì)象的時(shí)候,實(shí)際上new一個(gè)UserRepository
區(qū)實(shí)現(xiàn),這與直接調(diào)用UserRepository
無(wú)差別,IUserRepository
失去存在的意義. - 如果未來我們需要修改
UserRepository
類,但是UserService
依賴于它,這時(shí)候,我們需要修改所有依賴UserRepository
的類. - 有了這樣的依賴,很難對(duì)
UserService
進(jìn)行單元測(cè)試看尼。 - 與"高內(nèi)聚低耦合"的的原則背道而馳,這里可以看到服務(wù)層與倉(cāng)儲(chǔ)層有依賴.
為了解決這些問題于是就有了下面這個(gè)版本.
這就是工廠模式,實(shí)際上在abp之前我也經(jīng)常用這種方式,非常繁瑣,搭框架老是出錯(cuò),UserRepositoryFactory
是一個(gè)靜態(tài)類,創(chuàng)建并返回一個(gè)IUserRepository
UserService服務(wù)不需要直接去創(chuàng)建UserRepository.
這種方法雖然可以,但是依然存在一些問題.
-
UserService
依然依賴于UserRepositoryFactory
- 每一個(gè)倉(cāng)儲(chǔ)都有寫一個(gè)工廠,很繁瑣.
-
測(cè)試性還是不好.
解決辦法有幾種,包括屬性注入,構(gòu)造函數(shù)注入,和依賴注入框架等等.
上面就是abp中構(gòu)造函數(shù)注入與屬性輸入的完美運(yùn)用.現(xiàn)在,UserService
不知道哪些類實(shí)現(xiàn)userRepository
以及如何創(chuàng)建它描孟。誰(shuí)需要使用UserService
廉羔,首先創(chuàng)建一個(gè)IUserServiceUserService
并將其傳遞給構(gòu)造函數(shù)就可以了.
有人可能說userRepository
的從屬類里面可能存在依賴,依賴注入框架自動(dòng)化管理依賴關(guān)系都已經(jīng)解決了這些問題.構(gòu)造函數(shù)注入模式是一個(gè)完美的提供類的依賴關(guān)系的方式竹挡。通過這種方式好啰,你不能創(chuàng)建類的實(shí)例搅窿,而不提供依賴項(xiàng)。它也是一個(gè)強(qiáng)大的方式顯式地聲明是什么類的需求正確地工作借卧。
但是镰吵,在某些情況下勺馆,該類依賴于另一個(gè)類,但也可以沒有它紧卒。這通常是適用于橫切關(guān)注點(diǎn)(如日志記錄)盆佣。一個(gè)類可以沒有工作日志颤诀,但它可以寫日志如果你提供一個(gè)日志對(duì)象崖叫。在這種情況下养叛,您可以定義依賴為公共屬性,而不是讓他們放在構(gòu)造函數(shù),上面例子中NullLogger.Instance
是一個(gè)單例對(duì)象掉缺,實(shí)現(xiàn)了ILogger接口丑瞧,但實(shí)際上什么都沒做(不寫日志获雕。它實(shí)現(xiàn)了ILogger實(shí)例仓蛆,且方法體為空),在我們需要寫日志的地方,我們只需要UserService.Logger = new Log4NetLogger();
如此,我們就可以寫入日志了,如果不寫就不調(diào)用,因此是一個(gè)可選的依賴.
幾乎所有的依賴注入框架都支持屬性注入模式
ABP的依賴注入基于 Castle Windsor
框架睁冬。Castle Windsor
最成熟的DI框架之一。依賴注入的框架還有好多看疙,如Unity豆拨,Ninject,StructureMap能庆,Autofac
等,之前我用過Unity其他的幾個(gè)沒有研究過,依賴框架都可以自動(dòng)解決依賴關(guān)系施禾。他們可以創(chuàng)建所有依賴項(xiàng)(遞歸地依賴和依賴關(guān)系)。所以你只需要根據(jù)注入模式寫類和類構(gòu)造函數(shù)&屬性搁胆,其他的交給DI框架處理弥搞!在良好的應(yīng)用程序中邮绿,類甚至獨(dú)立于DI框架。整個(gè)應(yīng)用程序只會(huì)有幾行代碼或類攀例,顯示的與DI框架交互船逮。
有人說上面這個(gè)例子看不出來依賴注入啊,其實(shí)這里UserService是繼承自IUserService
,而IUserService
繼承自IApplicationService
,abp在IApplicationService
封裝了很多東西,ABP會(huì)自動(dòng)注冊(cè)它,因?yàn)樗鼘?shí)現(xiàn)IApplicationService
接口(它只是一個(gè)空的接口)粤铭。它會(huì)被注冊(cè)為transient (每次使用都創(chuàng)建實(shí)例)挖胃。當(dāng)你注入(使用構(gòu)造函數(shù)注入)IUserService
接口成一個(gè)類,UserService
對(duì)象會(huì)被自動(dòng)創(chuàng)建并傳遞給構(gòu)造函數(shù)梆惯。
命名約定在這里非常重要酱鸭。例如你可以將名字PersonAppService
改為 MyPersonAppService
或另一個(gè)包含“PersonAppService”后綴的名稱,由于IPersonAppService
包含這個(gè)后綴加袋。但是你可以不遵循PeopleService
命名您的服務(wù)類凛辣。如果你這樣做,它將不會(huì)為IPersonAppService
自動(dòng)注冊(cè)(它需要自注冊(cè)(self-registration
)到DI框架职烧,而不是接口)扁誓,所以,如果你想要你應(yīng)該手動(dòng)注冊(cè)它.
倉(cāng)儲(chǔ)
上一章我們已經(jīng)定義實(shí)體類,和DTOs,在倉(cāng)儲(chǔ)中可以直接調(diào)用,倉(cāng)儲(chǔ)是在領(lǐng)域?qū)雍蛿?shù)據(jù)映射層的中介,使用類似集合的接口來存取領(lǐng)域?qū)ο?
接口:
實(shí)現(xiàn):
在例子中IRepository
繼承自abp已經(jīng)封裝好的IRepository<TEntity>
中,在IRepository<TEntity>
中已經(jīng)為我們封裝好了許多方法,這就省得我們?cè)跒槊恳粋€(gè)倉(cāng)儲(chǔ)創(chuàng)建不同的方法了,這點(diǎn)很好如下圖.
包含了各式各樣的方法,如增刪查改等方法.還有一些Async的異步方法.GetAll返回
IQueryable<T>
類型的對(duì)象蚀之。因此我們可以在調(diào)用完這個(gè)方法之后進(jìn)行Linq操作.現(xiàn)在項(xiàng)目中運(yùn)用的是EF框架,所以如果ORM框架沒有提供Async的倉(cāng)儲(chǔ)方法則它會(huì)以同步的方式操作蝗敢。同樣地,舉例來說,
InsertAsync
操作起來和EF的新增是一樣的,因?yàn)镋F會(huì)直到單元作業(yè)(unit of work
)完成之后才會(huì)寫入新實(shí)體到數(shù)據(jù)庫(kù)中(DbContext.SaveChanges
)。數(shù)據(jù)庫(kù)連接的開啟和關(guān)閉足删,在倉(cāng)儲(chǔ)方法中,ABP會(huì)自動(dòng)化的進(jìn)行連接管理.當(dāng)倉(cāng)儲(chǔ)方法被調(diào)用后,數(shù)據(jù)庫(kù)連接會(huì)自動(dòng)開啟且啟動(dòng)事務(wù)寿谴。當(dāng)倉(cāng)儲(chǔ)方法執(zhí)行結(jié)束并且返回以后,所有的實(shí)體變化都會(huì)被儲(chǔ)存, 事務(wù)被提交并且數(shù)據(jù)庫(kù)連接被關(guān)閉,一切都由ABP自動(dòng)化的控制。如果倉(cāng)儲(chǔ)方法拋出任何類型的異常,事務(wù)會(huì)自動(dòng)地回滾并且數(shù)據(jù)連接會(huì)被關(guān)閉失受。上述所有操作在實(shí)現(xiàn)了
IRepository
接口的倉(cāng)儲(chǔ)類所有公開的方法中都可以被調(diào)用讶泰。如果倉(cāng)儲(chǔ)方法調(diào)用其它倉(cāng)儲(chǔ)方法(即便是不同倉(cāng)儲(chǔ)的方法),它們共享同一個(gè)連接和事務(wù)。連接會(huì)由倉(cāng)儲(chǔ)方法調(diào)用鏈最上層的那個(gè)倉(cāng)儲(chǔ)方法所管理拂到。另外所有的倉(cāng)儲(chǔ)對(duì)象都是暫時(shí)性的痪署。這就是說,它們是在有需要的時(shí)候才會(huì)被創(chuàng)建。ABP大量的使用依賴注入兄旬,當(dāng)倉(cāng)儲(chǔ)類需要被注入的時(shí)候,新的類實(shí)體會(huì)由注入容器會(huì)自動(dòng)地創(chuàng)建.
返回簡(jiǎn)書總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期
前往博客園總目錄:ABP+AdminLTE+Bootstrap Table權(quán)限管理系統(tǒng)一期