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事件,我的尚未找到具体差异,后续还须要从底层代码来看差异,暂时没有看出,有知道的朋友,烦请告知下,谢谢!

相关文章
相关标签/搜索