返回總目錄:ABP+AdminLTE+Bootstrap Table權限管理系統一期
AbpModule
在ABP框架中,倉儲,服務,這塊算是最為重要一塊之一了.ABP框架提供了創建和組裝模塊的基礎,一個模塊能夠依賴於另一個模塊,一個程序集可看成一個模塊,
一個模塊可以通過一個類來定義這個模塊,而給定義這個類要繼承自已經瘋轉好的AbpModule..net通過反射來獲取這些程序集中的類或者方法
模塊的調用往往涉及到先后順序,如果模塊A依賴於模塊B,那么模塊B要在模塊A之前初始化,初始化就相當於注冊,如使用IocManager對登記類進行注冊,
上面這個方法我們就把MyModule1 注入到MyModule2中了,在調用MyModule2的時候可以初始化MyModule1 .
什么是依賴注入呢?百科是這樣說:“依賴注入是一種軟件設計模式,一個或多個依賴項(或服務)被注入或通過引用傳遞到一個依賴對象,並且成為客戶端狀態的一部分。這種模式把客戶端依賴項的創建從它自己的行為中分離出來,允許程序設計成松耦合的,遵循依賴倒置和單一職責的原則。和服務定位器模式相比,它允許客戶端知道他們使用的系統查找依賴項。”
不使用依賴注入技術,很難管理依賴項和發布一個結構良好的應用。
倉儲(repository)
假設我們有一個應用程序服務,使用倉儲(repository)類插入實體到數據庫。在這種情況下,應用程序服務類依賴於倉儲(repository)類,如下
UserService使用UserRepository插入Person到數據庫。但是這段代碼有一些問題:
1,服務層UserService通過接口IUserRepository調用CreatePerson實現新增一個User對象,看似調用了IUserRepository接口,但是實際上還是依賴於倉促層的UserRepository.
2,UserService通過IUserRepository創建對象的時候,實際上new一個UserRepository區實現,這與直接調用UserRepository無差別,IUserRepository失去存在的意義.
3,如果未來我們需要修改UserRepository類,但是UserService依賴於它,這時候,我們需要修改所有依賴UserRepository的類.
4,有了這樣的依賴,很難對UserService進行單元測試。
5,與"高內聚低耦合"的的原則背道而馳,這里可以看到服務層與倉儲層有依賴.
為了解決這些問題於是就有了下面這個版本.
這就是工廠模式,實際上在abp之前我也經常用這種方式,非常繁瑣,搭框架老是出錯,UserRepositoryFactory是一個靜態類,創建並返回一個IUserRepository
UserService服務不需要直接去創建UserRepository.
這種方法雖然可以,但是依然存在一些問題.
1,UserService依然依賴於UserRepositoryFactory
2,每一個倉儲都有寫一個工廠,很繁瑣.
3,測試性還是不好.
依賴注入
解決辦法有幾種,包括屬性注入,構造函數注入,和依賴注入框架等等.
上面就是abp中構造函數注入與屬性輸入的完美運用.現在,UserService不知道哪些類實現userRepository以及如何創建它。誰需要使用UserService,首先創建一個IUserServiceUserService並將其傳遞給構造函數就可以了.
有人可能說userRepository的從屬類里面可能存在依賴,依賴注入框架自動化管理依賴關系都已經解決了這些問題.構造函數注入模式是一個完美的提供類的依賴關系的方式。通過這種方式,你不能創建類的實例,而不提供依賴項。它也是一個強大的方式顯式地聲明是什么類的需求正確地工作。
但是,在某些情況下,該類依賴於另一個類,但也可以沒有它。這通常是適用於橫切關注點(如日志記錄)。一個類可以沒有工作日志,但它可以寫日志如果你提供一個日志對象。在這種情況下,您可以定義依賴為公共屬性,而不是讓他們放在構造函數,上面例子中NullLogger.Instance 是一個單例對象,實現了ILogger接口,但實際上什么都沒做(不寫日志。它實現了ILogger實例,且方法體為空),在我們需要寫日志的地方,我們只需要UserService.Logger = new Log4NetLogger();如此,我們就可以寫入日志了,如果不寫就不調用,因此是一個可選的依賴.
幾乎所有的依賴注入框架都支持屬性注入模式
ABP的依賴注入基於 Castle Windsor框架。Castle Windsor最成熟的DI框架之一。依賴注入的框架還有好多,如Unity,Ninject,StructureMap,Autofac等,之前我用過Unity其他的幾個沒有研究過,依賴框架都可以自動解決依賴關系。他們可以創建所有依賴項(遞歸地依賴和依賴關系)。所以你只需要根據注入模式寫類和類構造函數&屬性,其他的交給DI框架處理!在良好的應用程序中,類甚至獨立於DI框架。整個應用程序只會有幾行代碼或類,顯示的與DI框架交互。
有人說上面這個例子看不出來依賴注入啊,其實這里UserService是繼承自IUserService,而IUserService繼承自IApplicationService,abp在IApplicationService封裝了很多東西,ABP會自動注冊它,因為它實現IApplicationService接口(它只是一個空的接口)。它會被注冊為transient (每次使用都創建實例)。當你注入(使用構造函數注入)IUserService接口成一個類,UserService對象會被自動創建並傳遞給構造函數。
命名約定在這里非常重要。例如你可以將名字PersonAppService改為 MyPersonAppService或另一個包含“PersonAppService”后綴的名稱,由於IPersonAppService包含這個后綴。但是你可以不遵循PeopleService命名您的服務類。如果你這樣做,它將不會為IPersonAppService自動注冊(它需要自注冊(self-registration)到DI框架,而不是接口),所以,如果你想要你應該手動注冊它.
上一章我們已經定義實體類,和DTOs,在倉儲中可以直接調用,倉儲是在領域層和數據映射層的中介,使用類似集合的接口來存取領域對象.
接口:
實現:
在例子中IRepository繼承自abp已經封裝好的IRepository<TEntity>中,在IRepository<TEntity>中已經為我們封裝好了許多方法,這就省得我們在為每一個倉儲創建不同的方法了,這點很好如下圖.
包含了各式各樣的方法,如增刪查改等方法.還有一些Async的異步方法.GetAll返回IQueryable<T>類型的對象。因此我們可以在調用完這個方法之后進行Linq操作.
現在項目中運用的是EF框架,所以如果ORM框架沒有提供Async的倉儲方法則它會以同步的方式操作。同樣地,舉例來說,InsertAsync操作起來和EF的新增是一樣的,因為EF會直到單元作業(unit of work)完成之后才會寫入新實體到數據庫中(DbContext.SaveChanges)。
數據庫連接的開啟和關閉,在倉儲方法中,ABP會自動化的進行連接管理.當倉儲方法被調用后,數據庫連接會自動開啟且啟動事務。當倉儲方法執行結束並且返回以后,所有的實體變化都會被儲存, 事務被提交並且數據庫連接被關閉,一切都由ABP自動化的控制。如果倉儲方法拋出任何類型的異常,事務會自動地回滾並且數據連接會被關閉。上述所有操作在實現了IRepository接口的倉儲類所有公開的方法中都可以被調用。如果倉儲方法調用其它倉儲方法(即便是不同倉儲的方法),它們共享同一個連接和事務。連接會由倉儲方法調用鏈最上層的那個倉儲方法所管理。
另外所有的倉儲對象都是暫時性的。這就是說,它們是在有需要的時候才會被創建。ABP大量的使用依賴注入,當倉儲類需要被注入的時候,新的類實體會由注入容器會自動地創建.