ASP.NET Core 3.1系列(26)——Autofac中的实例生命周期

32 篇文章 43 订阅

1、前言

前面的博客主要介绍了Autofac中的一些注册方法,下面就来介绍一下Autofac中实例的生命周期。之前在介绍ASP.NET Core内置IoC容器的时候说过,实例的生命周期有:瞬时生命周期域生命周期全局单例生命周期,而Autofac在这三种周期之上又新增了若干周期模式,下面开始介绍。

2、Autofac中的生命周期

2.1、InstancePerDependency

InstancePerDependency表示瞬时生命周期,它是Autofac中默认的周期模式,在瞬时生命周期中,容器每次都会创建新的实例,代码如下:

using Autofac;
using System;

namespace App
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 注册接口和类
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Cat>().As<IAnimal>().InstancePerDependency();

            // 构建容器
            IContainer container = builder.Build();

            // scope1
            using (var scope = container.BeginLifetimeScope())
            {
                IAnimal obj1 = scope.Resolve<IAnimal>();
                IAnimal obj2 = scope.Resolve<IAnimal>();
                Console.WriteLine(obj1.GetHashCode());
                Console.WriteLine(obj2.GetHashCode());
            }

            Console.WriteLine("---------");

            // scope2
            using (var scope = container.BeginLifetimeScope())
            {
                IAnimal obj3 = scope.Resolve<IAnimal>();
                IAnimal obj4 = scope.Resolve<IAnimal>();
                Console.WriteLine(obj3.GetHashCode());
                Console.WriteLine(obj4.GetHashCode());
            }
        }
    }
}

运行结果如下所示:

43527150
56200037
---------
36038289
55909147

可以发现:obj1obj2obj3obj4的哈希值均不相同,因此它们是不同的实例。

2.2、InstancePerLifetimeScope

InstancePerLifetimeScope表示域生命周期。域周期表示在同一个域中,每个实例都是相同的,而不同域中的实例又是不同的,因此可以理解为在域中实现了单例模式,代码如下:

using Autofac;
using System;

namespace App
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 注册接口和类
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Cat>().As<IAnimal>().InstancePerLifetimeScope();

            // 构建容器
            IContainer container = builder.Build();

            // scope1
            using (var scope = container.BeginLifetimeScope())
            {
                IAnimal obj1 = scope.Resolve<IAnimal>();
                IAnimal obj2 = scope.Resolve<IAnimal>();
                Console.WriteLine(obj1.GetHashCode());
                Console.WriteLine(obj2.GetHashCode());
            }

            Console.WriteLine("---------");

            // scope2
            using (var scope = container.BeginLifetimeScope())
            {
                IAnimal obj3 = scope.Resolve<IAnimal>();
                IAnimal obj4 = scope.Resolve<IAnimal>();
                Console.WriteLine(obj3.GetHashCode());
                Console.WriteLine(obj4.GetHashCode());
            }
        }
    }
}

运行结果如下所示:

43527150
43527150
---------
56200037
56200037

可以发现:obj1obj2的哈希值相同,obj3obj4的哈希值相同,因此obj1obj2为同一实例,obj3obj4为同一实例。

2.3、InstancePerMatchingLifetimeScope

InstancePerMatchingLifetimeScope也表示域生命周期,它允许开发者做更精细的控制,那么它与InstancePerLifetimeScope的区别在哪里?来看下面一段代码:

using Autofac;
using System;

namespace App
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 注册接口和类
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Cat>().As<IAnimal>().InstancePerLifetimeScope();

            // 构建容器
            IContainer container = builder.Build();

            // scope1
            using (var scope = container.BeginLifetimeScope())
            {
                IAnimal obj1 = scope.Resolve<IAnimal>();
                IAnimal obj2 = scope.Resolve<IAnimal>();
                Console.WriteLine(obj1.GetHashCode());
                Console.WriteLine(obj2.GetHashCode());

                Console.WriteLine("---------");

                // 子域
                using (var scope1 = scope.BeginLifetimeScope())
                {
                    IAnimal obj3 = scope1.Resolve<IAnimal>();
                    IAnimal obj4 = scope1.Resolve<IAnimal>();
                    Console.WriteLine(obj3.GetHashCode());
                    Console.WriteLine(obj4.GetHashCode());
                }
            }
        }
    }
}

上面的代码设置为InstancePerLifetimeScope模式,在域scope中又创建了一个子域scope1,运行结果如下:

43527150
43527150
---------
56200037
56200037

可以发现:子域中的obj3obj4的哈希值相同,但它们与obj1obj2的哈希值却不相同。因此obj1obj2为同一实例,obj3obj4为同一实例。现在切换为InstancePerMatchingLifetimeScope模式,代码如下:

using Autofac;
using System;

namespace App
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 注册接口和类
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Cat>().As<IAnimal>().InstancePerMatchingLifetimeScope("abc");

            // 构建容器
            IContainer container = builder.Build();

            // scope1
            using (var scope = container.BeginLifetimeScope("abc"))
            {
                IAnimal obj1 = scope.Resolve<IAnimal>();
                IAnimal obj2 = scope.Resolve<IAnimal>();
                Console.WriteLine(obj1.GetHashCode());
                Console.WriteLine(obj2.GetHashCode());

                Console.WriteLine("---------");

                // 子域
                using (var scope1 = scope.BeginLifetimeScope())
                {
                    IAnimal obj3 = scope1.Resolve<IAnimal>();
                    IAnimal obj4 = scope1.Resolve<IAnimal>();
                    Console.WriteLine(obj3.GetHashCode());
                    Console.WriteLine(obj4.GetHashCode());
                }
            }
        }
    }
}

上面的代码在注册时打了一个标签,名称为abc,然后通过该标签名称创建域scope,运行结果如下所示:

43527150
43527150
---------
43527150
43527150

可以发现:obj1obj2obj3obj4的哈希值均相同,它们为同一实例。因此可以这样理解:如果将生命周期设置为InstancePerMatchingLifetimeScope模式,那么在该域中,不管创建了多少子域,它们都会调用同一实例。

2.4、InstancePerRequest

InstancePerRequest表示在每次HTTP请求内实现单例。该周期模式只适用于Web项目,由于本文的例子基于控制台程序,因此不太方便举例说明。本质上这也是一种域内单例的周期模式,但并不经常使用。

2.5、InstancePerOwned

关于InstancePerOwned周期,相关的介绍不多,我在这里就凭借自己的一点理解来进行说明,如果有不对的地方还请大家指出来。首先新增一个类Zoo,代码如下:

namespace App
{
    public class Zoo
    {
        protected readonly IAnimal _animal;

        public Zoo(IAnimal animal)
        {
            _animal = animal;
        }

        public string Get()
        {
            return _animal.GetMsg();
        }
    }
}

然后在Autofac中注册该类,代码如下:

using Autofac;
using System;

namespace App
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 注册接口和类
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Zoo>();
            builder.RegisterType<Cat>().As<IAnimal>();

            // 构建容器
            IContainer container = builder.Build();

            // scope1
            using (var scope = container.BeginLifetimeScope())
            {
                var cat = scope.Resolve<IAnimal>();
                Console.WriteLine(cat.GetMsg());

                var zoo = scope.Resolve<Zoo>();
                Console.WriteLine(zoo.Get());
            }
        }
    }
}

运行结果如下所示:

This is cat
This is cat

上面这段代码很简单,现在把代码改一下,把InstancePerOwned周期加进来:

using Autofac;
using System;

namespace App
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 注册接口和类
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Zoo>();
            builder.RegisterType<Cat>().As<IAnimal>().InstancePerOwned<Zoo>();

            // 构建容器
            IContainer container = builder.Build();

            // scope
            using (var scope = container.BeginLifetimeScope())
            {
                var cat = scope.Resolve<IAnimal>();
                Console.WriteLine(cat.GetMsg());

                var zoo = scope.Resolve<Zoo>();
                Console.WriteLine(zoo.Get());
            }
        }
    }
}

运行代码,程序报错,发现在创建Cat实例的时候发生异常,如下图所示:

在这里插入图片描述
这是因为InstancePerOwned模式会对Cat实例的创建做出限制:

builder.RegisterType<Cat>().As<IAnimal>().InstancePerOwned<Zoo>();

根据我对官方文档的理解,上面这行代码可以理解为:Cat实例的创建依赖于Zoo实例的创建。当Zoo实例被创建后,容器会自动创建Cat实例,同时在域scope内无法单独使用Cat实例,它只能在Zoo实例的内部进行调用。因此开发者无法在域scope内手动调用Resolve方法生成Cat实例。下面修改一下代码:

using Autofac;
using Autofac.Features.OwnedInstances;
using System;

namespace App
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 注册接口和类
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Zoo>();
            builder.RegisterType<Cat>().As<IAnimal>().InstancePerOwned<Zoo>();

            // 构建容器
            IContainer container = builder.Build();

            // scope
            using (var scope = container.BeginLifetimeScope())
            {
                var zoo = scope.Resolve<Owned<Zoo>>();
                Console.WriteLine(zoo.Value.Get());
                zoo.Dispose();
            }
        }
    }
}

运行结果如下所示:

This is cat

在使用InstancePerOwned周期时,我们需要使用Owned<>来接收容器创建的实例,然后对Value属性进行操作。在上面的代码中,当调用Resolve<Owned<Zoo>>时,Cat实例就会被自动创建。但无法直接调用。对象使用完后需要手动调用Dispose方法对其进行销毁。

2.6、SingleInstance

SingleInstance表示全局单例生命周期,这个比较好理解,即:所有创建的实例均为同一实例,代码如下:

using Autofac;
using System;

namespace App
{
    internal class Program
    {
        static void Main(string[] args)
        {
            // 注册接口和类
            ContainerBuilder builder = new ContainerBuilder();
            builder.RegisterType<Cat>().As<IAnimal>().SingleInstance();

            // 构建容器
            IContainer container = builder.Build();

            // scope1
            using (var scope = container.BeginLifetimeScope())
            {
                IAnimal obj1 = scope.Resolve<IAnimal>();
                IAnimal obj2 = scope.Resolve<IAnimal>();
                Console.WriteLine(obj1.GetHashCode());
                Console.WriteLine(obj2.GetHashCode());
            }

            Console.WriteLine("---------");

            // scope2
            using (var scope = container.BeginLifetimeScope())
            {
                IAnimal obj3 = scope.Resolve<IAnimal>();
                IAnimal obj4 = scope.Resolve<IAnimal>();
                Console.WriteLine(obj3.GetHashCode());
                Console.WriteLine(obj4.GetHashCode());
            }
        }
    }
}

运行结果如下所示:

43527150
43527150
---------
43527150
43527150

3、结语

本文主要介绍了Autofac中实例的生命周期。一般情况下,瞬时单例三种周期模式应用较多,而其他的周期模式则相对较少,有兴趣的同志可以查看Autofac官方文档进行深入了解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值