先說下爲何翻譯這篇文章,既定的方向是架構,而後爲了學習架構就去學習一些架構模式、設計思想。數據庫
忽然有一天發現依賴注入這種技能。爲了使得架構可測試、易維護、可擴展,須要架構設計爲鬆耦合類型,簡單的說也就是解耦。爲了解耦前面的人提出各類理論,主要思想是控制反轉,而如今主流的主要是兩個:依賴注入、服務定位(有篇英文文章特地討論這種模式,最終的結論是否認的,乍看了一眼,沒看懂)數組
有了某個思想即可以在程序中體現,用多了,人們就去對它進行封裝,普通的人封裝的大概就本身用,高人封裝了便成了組件。如今基本上都在弄 .net ,因此說的技術也基本上是這一塊的。.net 的 IOC 框架有 Autofac、Castle Windsor、Unity、Spring.NET、StructureMap、Ninject。session
有這麼多框架爲何選 Autofac,我在這個地方只是學習這種 IOC 思想的框架,並無真實的用在生產中。Autofac 各方面的的性能都比較中庸,因此用它做爲 IOC 入門應該是比較合適的,這樣也就致使這篇文章適合初學者閱讀。架構
接下來就要具體說下翻譯的原文,文章對於 Autofac 在 IOC 思想的實現和 Autofac 如何使用作了十分透徹的說明,可是本人水平有限,一些地方沒有翻譯對,甚至翻譯錯了,這些我特地指明,省的坑了各位,若是發現不對直接參考原文,但也請告知我,以便改正。app
原文地址:http://www.codeproject.com/Articles/25380/Dependency-Injection-with-Autofac框架
----------------------------------------------------------------------------------------------------------------------------------------------函數
Dependency Injection with Autofac性能
使用 Autofac 進行依賴注入學習
目錄測試
Autofac 是發佈在 Google Code 上的依賴注入或控制反轉的開源容器。
Autofac 與許多相似技術不一樣的是它堅持儘量的使用純質的 C# 語法。【也就說不去依賴其它的組件,從而使得 Autofac 有着更好的兼容性】
等等
這個程序是一個控制檯程序,它檢查一個備忘錄列表,每個備忘錄有一個過時日期,程序向用戶提醒哪些過時的備忘錄。
如下幾點做爲使用依賴注入的直接緣由:
1 以參數接收全部依賴的對象
2 獨立的持久化-IQueryable 對象多是數據庫表、一個結構文件,再或者內存集合。(集合公佈)
3 提醒用戶的形式是獨立的。(以接口控制)
這些舉措使得這個類容易測試,可配置的而且是可維護的。
IQueryable 接口在 dotnet 3.5 中引入,它適合做爲備忘錄的數據源。由於它能夠同時用於內存對象和關係型數據庫的查詢。
應用程序最基礎的結構以下:
本文主要關注的是 MemoCHecker 如何獲取與它關聯的 notifier 和 memo 服務,以及每一個被依賴的對象如何獲取他們的實體。【有個反轉的概念】
更重要的是,它很難去切換不一樣的實現服務;好比可能用 EmailNotifier 替換 printing notifier,可是原有的會有依賴,或許不一樣來源於這些 PrintingNotifier【不理解】,但也有多是與依賴的其它組件有交互。(這也多是這些組合現成的問題,而它自己就值得寫文說明)
Autofac 和其它的依賴組件經過在配置時「扁平化」深度網狀對象圖。【待譯】
當使用 Autofac,訪問 MemoChecker 是分離的來源於如下建立方式:
Container.Resolve() 執行請求一個 MemoChecker 的實例,它負責實例的實例化和準備使用。那麼,容器是如何工做的、如何建立 MemoChecker 實例。
依賴注入容器是一個把服務映射到組件的集合。在這種情形下,服務是用來識別某一特定的功能,它能夠是一個文本標籤,但其一般是某個接口。
註冊器在系統內部捕獲組件動態的行爲。其最受關注點是如何建立組件的實例。
Autofac 可以接受建立組件的註冊方式有:表達式、提供實例和基於 System.Type 反射。【待譯】
下面就是爲 MemoChecker 組件設置一個註冊器:
每一條 Register() 語句僅只處理那些處於對象圖頂端的且其直接關聯到依賴對象上。
C=> new MemoChecker(…) 將被用於容器建立 MemoChecker 組件。
每一個 MemoChecker 依賴於額外的兩個服務:IQueryable<Memo> 和 IMemoDueNotifier 。這些服務經過容器調用 Resolve() 方法在 lambda 表達式內檢索到,容器是經過參數 c 傳遞過來的。
上面的註冊器並無對 IQueryabl<Meno> 和 IMemoDueNotifier 的實現進行任何說明。這兩個服務的配置依賴關係同 MemoChecker 的配置相似。
上面的表達式將被提供於 Register() 當其返回 MemoChecker 類型,因而,Autofac 會將其做爲這個註冊器的默認服務,除非有另外的更爲準確的 As() 方法,下面這個 As() 方法包含更爲明確的目的:
不管哪一種方式,某個 MemoChecker 實例的請求都將是調用咱們的表達式後的某一結果。
Autofac 不會在組件註冊時執行表達式,相反,它會等到 Resolve<MemoChecker>() 調用時執行表達式。這一點很關鍵,由於它除去了組件註冊的順序的依賴。【依賴關係不受註冊順序影響】
IQueryable<Memo> 服務由存在的 memos 實例提供,PrintingMemoNotifier 類最終指向 TextWriter 的實例 Console.Out 。
Memos 和 Console.Out 都以已經建立的實例提供給容器。(對於 ExternallyOwned() 的解釋,請參考 Deterministic Disposal)
Autofac 也能夠用其它容器建立組件的方式-反射來建立組件。(更多這個場景的優化伴隨着 MSIL-generation)
這種方式的含義是說你能夠告訴 Autofac 有關於提供服務的類型,而且容器將會使用最合適的構造函數,以及根據其它可用的服務來選擇參數。
MemoChecker 註冊能夠被下面的形式替換:
通常說來,最多見的作法是使用自動鏈接去註冊某一批次的組件。【待譯】
這種方式使得大量的組件可使用但沒有繁重的註冊每個組件的消耗,而且你須要清楚的思考這種情形。Autofac 提供以下快捷的方式批次註冊組件:
自動鏈接在以程序 XML 配置文件註冊組件時也特別實用。
在請求 MemoChecker 服務以前程序建立註冊組件以下所示:
在上面的配置代碼中沒有嵌套顯示了「扁平」的依賴結構而這些由容器提供。
這彷佛很難看到上面這種註冊方式比手動的例子更爲之間的對象結構,但請再次回憶起,這個示例比日常的系統擁有更少的組件。
最爲重要的區別是如今每一個組件的配置都獨立於全部其餘的組件。伴隨着更多的組件添加到系統中,他們能夠被理解爲純淨的按照這些服務所暴露的河這些服務所須要的。這是一種有效的控制架構複雜化的手段。
IDisposable 兼具祝福和詛咒。組件有一致的方式去同其應當被清理交互這是好的。不幸的是,哪一個組件在何時應當被清理並不老是很容易肯定。
這個問題因爲容許相同的服務有不一樣的實現而變得糟糕。在這個示例中,IMemoDueNotifier 有許多不一樣的實現可能被部署。其中的一些將有工廠建立,一些將會是單例的形式,一些將會被清理,還有一些將不會被清理。
組件做爲一個通告者是沒有辦法決定它們應當嘗試把它丟給 IDisposable 和調用 Dispose() 或者是不這樣作。各類記錄的結果是致使易錯的河繁瑣的。
Autofac 使用經過容器跟蹤建立的全部能夠清理對象方式解決這個問題。記錄的示例以下:
容器在一個 using 程序塊中,由於它擁有全部它建立的組件的全部權,而且清理它們當容器被清理的時候。
這一點很重要由於它真正實現了從配置關注分離的精神【待譯】,MemoChecker 服務能夠在任何須要它的時候使用,甚至是以另外被依賴的組件角色被直接建立,不用擔憂它們是否應當被清理。
伴隨着這個帶來的心裏的平靜,你甚至不用來回讀示例程序來發現任何須要實現 IDisposable (實際是沒有)的類,由於你能夠依賴容器去作正確的事情。
Disabling Disposal
記住 ExternallyOwned() 子句在上面完整的示例中添加到 Console.Out 的註冊上。這是合意的由於 Console.Out 是可清理的,但這個時候容器不該當去清理它。
容器將會正常的存在於應用程序執行期間,而且在相同應用程序長生命週期內清理它是一個很好的方式去釋放組件所擁有的資源。大多數不平凡的程序也應釋放資源在一些其它的時候,如:Http 請求完成、工做線程退出或者一個用戶會話結束。
Autofac 使用嵌套的生命週期域幫助你管理這些生命週期,代碼以下:
生命週期管理是經過註冊組件實例映射到生命週期域實現的。
Autofac 容許你指定一個組件多少實例能夠駐留以及它們將如何在其它組件間共享。
控制組件獨立的定義做用域是一個很是重要的改進對於傳統方法使用靜態 Instance 屬性來定義單例。這個區別在於對象是什麼和如何使用對象。【待譯】
使用 Autofac 最經常使用生命週期設置以下:
單例
每一依賴一個實例
每一輩子命做用域一個實例
單例生命週期,它將是大多數組件只有一個實例在容器中的選擇,而且實例會隨着建立它的容器清理時被清理。
一個組件可使用 SingleInstance() 修飾配置爲這種生命週期,以下所示:
每次這樣的組件從容器請求時,都會返回相同的實例:
當組件註冊時沒有特地指定生命週期,將會默認 instance-per-dependency 生命週期。每次從容器獲取這樣的組件時,都會返回新建的實例:
某個使用這種生命週期的組件將會跟隨着組件被建立的生命週期而被清理。若是一個 per-dependency 組件被請求是去構造一個 single-instance 組件,對於這種例子,那麼 per-denpendency 組件將會隨着 single-instance 組件對於容器的生命週期一直存在。
這種方式知足每一線程、每一請求或者每一事務組件的生命週期的靈活需求。簡單建立一個生命做用域能夠生存在必須的生命週期持續的週期。【待譯】來自相同的做用域請求將會獲得相同的實例,同時來自不一樣做用域的請求將會獲得不一樣的實例。
組件間的依賴僅只在其知足其它的組件在其相同的做用域或者在其外部(父)做用域才能創建。這樣確保組件間的依賴在其沒有創建前被處理掉。【待譯】若是 application、session 和Request 有着嵌套的需求,那麼可能會按照以下的方式建立:
在這個示例中請知道,appContainer 將會建立許多子 sessionLifetime,而且每一個 session 同appContainer 同樣會有許多子 controller。【待譯】
在這個場景,容許依賴的方向是 Request -> session -> application。用於處理用戶請求的組件能夠引用任何其餘的組件。可是依賴關係在相反的方向上是不被容許的,因此,對於這個狀況,應用程序級別的 single-instance 組件將不會鏈接到指定單例用戶 session 的組件。【待譯】
在這樣的層次結構中,Autofac 老是服務於 shortest-lived 生命週期的組件請求。這將會日常的請求生命週期。【待譯】Single-instance 組件將會駐留在應用程序級別,來將組件的生命週期關聯到 session 級別,詳情請參考 wiki。【待譯】
Autofac 的做用域模式是靈活和有效的。做用域和嵌套生命週期間的關係使得註冊龐大的依賴成員成爲可能。
依賴注入是一種極其強大的結構控制機制,可是想要獲取這些優點,系統的組件經過容器成爲其它組件能用的佔比十分重要。
到目前爲止 Autofac 所描述的特徵都是被設計爲獲取存在的,當「老的簡樸的」 .Net 組件添加到容器中,不須要修改或適配代碼。
使用表達式來向容器註冊組件在使用 Autofac 的應用程序中。一些示例場景說明這些由 Autofac 實現的:
已經存在的工廠方法能夠用表達式的形式使用:
已經存在須要在第一次訪問時加載的單例可使用表達式註冊,而且它的加載是延遲的:
傳遞給組件的參數可使任何的來源:
某個類型的實現甚至能夠根據參數來決定:
集成,在這裏的意思是使得已存在的類庫服務和程序組件經過容器使他們可使用。
Autofac 支持一些典型場景的集成好比在 ASP.Net 應用程序中使用的那樣;然而,Autofac 模型的靈活性產生了大量的繁瑣的集成工做,於是最好的方式是把這些留給程序設計者在他們程序最合適的地方實現。
基於表達式的註冊和指定的清理以及延遲加載組件的方案,能夠產生使人驚奇的效果當它們集成在一塊兒時:
這是一個 WCF client 集成自 Autofac 網站的示例。ITrackListing 和 IChannelFactory<ITrackkListing> 這兩個關鍵的服務,WCF 管道對於這些通用的 bit 流很容易基於表達式進行註冊。【待譯】
一些要點以下:
Channel 工廠只有在其須要的時候建立,可是一旦建立,它將保留以在每一次 ITrackListing 請求時重用。
ITrackListing 不繼承自 IDisposable,但在 WCF 中,客戶端服務代理以這種方式建立須要聯繫到 IDisposable 而且清理它。使用 ITRackListing 接口,使得仍然不知道其實現細節。
終端信息能夠來自任何地方-任意服務、數據庫或者某個配置文件。
除了使用基本的 Register() 方法沒有其餘概念引入。
這小節向你展現 Autofac 是如何工做的,使得你集中於實現你的應用程序,而不是擴展或驚奇 DI 容器的複雜性。
我但願這篇文章用來講明來學習如何使用 Autofac 的各類要點,接下來的步驟多是:
下載源代碼
在 Wiki 上閱讀更多文章
在論壇裏介紹你本身