autofac
Autofac是一套高效的依賴注入框架。javascript
Autofac官方網站:http://autofac.org/html
Autofac在Github上的開源項目:https://github.com/autofac/Autofacjava
Autofac安裝:經過VS的Nuget能夠很方便的獲取。git
生命週期事件
autofac爲註冊的類型對象提供了一套生命週期事件,覆蓋了一個類型從註冊到最後「釋放」的一套事件。有了這些事件,咱們能夠相對方便的在類型對象的各個階段進行AOP操做。github
OnRegistered
在類型註冊成功後觸發,也就是在調用ContainerBuilder的Build方法時,其方法內部觸發的。OnRegistered的委託參數類型爲ComponentRegisteredEventArgs,其中包含了類型註冊後的底層配置信息,此處不對配置信息作介紹,平常通常不會使用這寫參數。若是咱們但願在類型註冊到autofac中後執行一些操做,咱們能夠經過OnRegistered事件達到目的。關於此事件,在autofac官網上沒有相關說明。框架
var builder = new ContainerBuilder(); builder .RegisterType<A>() //class A { } .OnRegistered(e => { Console.WriteLine(e); }); builder.Build(); //會觸發OnRegistered事件
OnPreparing
在調用Resolve時觸發,具體觸發時機,是根據Resolve的類型獲取到類型相關配置時觸發的,而這時,類型對象尚未實例化。OnPreparing委託參數類型爲PreparingEventArgs,該類型有三個屬性Component、Context、Parameter,其中Component爲Resolve類型的說明/配置,Parameter爲Resolve時傳入的參數(詳見解析獲取傳參)。在OnPreparing中,咱們能夠修改傳入的Parameter值,甚至能夠以此修改實際調用的構造方法(經過Resolve對象構造方法選擇原則):網站
class Program { static void Main(string[] args) { var builder = new ContainerBuilder(); builder.RegisterType<A>() .OnPreparing(e => { // 1.不作任何處理時,最後輸出 result: 3 // 2.修改傳入值,最後輸出 result: 5 e.Parameters = new[] {new NamedParameter("x", 2), new NamedParameter("y", 3)}; // 3.修改參數類型,最後輸出 id: 7, name: 'undefined' e.Parameters = new Parameter[] {new PositionalParameter(0, 7), new TypedParameter(typeof (string), "undefined")}; // 4.直接不要參數,最後輸出 no parameter constructor e.Parameters = Enumerable.Empty<Parameter>(); }); var container = builder.Build(); container.Resolve<A>(new NamedParameter("x", 1), new NamedParameter("y", 2)); Console.Write("Press any key to continue..."); Console.ReadKey(); } }class A { public A() { Console.WriteLine("no parameter constructor"); } public A(int id, string name) { Console.WriteLine("id: {0}, name: '{1}'", id, name); } public A(int x, int y) { Console.WriteLine("result: {0}", x + y); } }OnPreparing事件在autofac官網上也沒有相關的說明,更多的用法待你們使用過程當中進行開荒了。ui
OnActivating & OnActived
OnActivating與OnActived是兩個不一樣的事件,這裏將它們放到一塊兒講,是由於它們有必定的類似之處,起初用起來還發現不了他們以前的區別,因此放在一塊兒進行對比說明。spa
相同點
與OnPreparing事件相同,OnActivating與OnActived也是在調用Resolve時觸發的,只是OnActivating與OnActived觸發是,類型實例已經建立,委託參數的類型雖然不一樣,可是都有且僅有四個相同類型的屬性Parameters、Component、Context、Instance,前三個參數與OnPreparing的委託參數屬性類型相同,最後一個Instance是根據Resolve傳入的類型實例化出來的實例對象,也就是最後Resolve方法返回的對象。代理
不一樣點
不一樣點主要有兩個,一個是它們的委託參數類型不一樣,雖然它們的屬性類型和個數都是相同的,可是OnActivating的委託參數還有一個ReplaceInstance方法,這個方法是用來替換最後返回的對象的,也就是相同點中說到的Instance屬性對象。可是須要注意,使用ReplaceInstance時,不是能夠替換爲任意類型,而是隻能替換爲相同類型或其子類:
var builder = new ContainerBuilder(); builder.RegisterType<C1>().As<IInterface>() .OnActivating(e => { //e.ReplaceInstance(new C2()); // 異常 //e.ReplaceInstance(new C1()); // 無異常 //e.ReplaceInstance(new CC1()); //無異常 }); var container = builder.Build(); var inter = container.Resolve<IInterface>();interface IInterface { } class C1 : IInterface { } class C2 : IInterface { } class CC1 : C1 { }ReplaceInstance方法是OnActivating與OnActived第一個不一樣點。關於第二個不一樣點,如今暫時只發現這個區別與自動屬性注入有關,由於自動屬性注入其實是做爲一個委託註冊到OnActivating或OnActived事件中的,爲何是或呢?由於根據調用PropertiesAutowired方法時,傳入的不一樣參數,這個委託將註冊不到不一樣事件上,若是不傳參或傳入PropertyWiringOptions.None,自動屬性注入,將會註冊到OnActivating事件上,不然將註冊到OnActived事件上。
關於PropertiesAutowired方法的參數,那是與環形依賴注入相關的,如今暫時不作說明,後續博文將會說明。
PropertiesAutowired註冊時機注意
由於自動屬性注入是註冊到事件上的,而後咱們又知道,註冊到事件上的委託,通常是順序調用的,因此須要注意PropertiesAutowired在註冊時調用的時機。好比寫到自定義註冊OnActivating事件前,且PropertiesAutowired方法不傳入參數,那麼自定義註冊的OnActivating事件觸發時,參數的Instance中自動注入的屬性將已經賦值,反之寫到自定義註冊OnActivating事件後,自動注入的屬性將爲賦值!(OnActived事件同理)
var builder = new ContainerBuilder(); builder.RegisterType<C1>() //.PropertiesAutowired() // 在OnActivating前,將輸出 OnActivating: not null .OnActivating(e => { // 輸出 OnActivating: null Console.WriteLine("OnActivating: " + (e.Instance.C2 == null ? "null" : "not null")); }) .PropertiesAutowired(); // 在OnActivating後,將輸出 OnActivating: null builder.RegisterType<C2>(); var container = builder.Build(); var c1 = container.Resolve<C1>();class C1 { public C2 C2 { get; set; } } class C2 { }官網說明
OnActivating與OnActived在autofac官網中有一些說明,能夠做爲參考:
OnActivating事件中推薦的三種操做:1.替換實例對象,或使用代理對象(經過ReplaceInstance方法);2.執行屬性注入或方法注入;3.執行其餘初始化任務。
OnActived事件中能夠執行一些應用程序級別的任務。
OnRelease
在生命範圍結束時調用,關於此事件,將在後續的單元控制文章中進行詳細說明,這裏暫時不作說明。
上面說的都是爲每一個類型註冊事件,可是若是咱們但願爲全部類型都註冊某一事件,有什麼方式來實現呢?
(首先申明,OnRelease事件暫時沒找到統一註冊的方式)
咱們能夠在builder註冊類型前使用RegisterCallback進行統一事件註冊,詳見代碼:
var builder = new ContainerBuilder(); builder.RegisterCallback(cr => { // 下面的Registered事件至關類型的OnRegistered事件 cr.Registered += (sender, eventArgs) => { // OnPreparing事件 eventArgs.ComponentRegistration.Preparing += (o, preparingEventArgs) => { }; // OnActivating事件 eventArgs.ComponentRegistration.Activating += (o, activatingEventArgs) => { }; // OnActivated事件 eventArgs.ComponentRegistration.Activated += (o, activatedEventArgs) => { }; }; }); // builder.RegisterType<...>... // ...
autofac提供的這些事件,咱們能夠很方便的進行AOP操做,好比經過統一事件註冊,咱們能夠很方便的進行日誌記錄。而關於OnActivating事件和OnActived事件,我的尚未找到具體差異,後續還須要從底層代碼來看差異,暫時沒有看出,有知道的朋友,煩請告知下,謝謝!