Autofac全面解析系列(版本:3.5) – [使用篇(推薦篇):5.生命週期事件]

前言

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第一個不一樣點。關於第二個不一樣點,如今暫時只發現這個區別與自動屬性注入有關,由於自動屬性注入其實是做爲一個委託註冊到OnActivatingOnActived事件中的,爲何是或呢?由於根據調用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事件,我的尚未找到具體差異,後續還須要從底層代碼來看差異,暫時沒有看出,有知道的朋友,煩請告知下,謝謝!

相關文章
相關標籤/搜索