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

news/2024/12/2 13:40:10/

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();// scope1using (var scope = container.BeginLifetimeScope()){IAnimal obj1 = scope.Resolve<IAnimal>();IAnimal obj2 = scope.Resolve<IAnimal>();Console.WriteLine(obj1.GetHashCode());Console.WriteLine(obj2.GetHashCode());}Console.WriteLine("---------");// scope2using (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();// scope1using (var scope = container.BeginLifetimeScope()){IAnimal obj1 = scope.Resolve<IAnimal>();IAnimal obj2 = scope.Resolve<IAnimal>();Console.WriteLine(obj1.GetHashCode());Console.WriteLine(obj2.GetHashCode());}Console.WriteLine("---------");// scope2using (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();// scope1using (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();// scope1using (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();// scope1using (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();// scopeusing (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();// scopeusing (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();// scope1using (var scope = container.BeginLifetimeScope()){IAnimal obj1 = scope.Resolve<IAnimal>();IAnimal obj2 = scope.Resolve<IAnimal>();Console.WriteLine(obj1.GetHashCode());Console.WriteLine(obj2.GetHashCode());}Console.WriteLine("---------");// scope2using (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官方文档进行深入了解。


http://www.ppmy.cn/news/11901.html

相关文章

【5】K8S_Deployment

目录 1、Deployment作用 2、deployment的冗余能力 3、deployment的多副本部署 4、deployment的扩缩容 5、deployment的自愈能力 6、滚动更新 7、版本回退 1、Deployment作用 控制Pod&#xff0c;使Pod拥有多副本&#xff0c;自愈&#xff0c;扩缩容等能力 2、deployme…

【算法数据结构初阶篇】:位运算

算法中很多情况下需要用到各种位运算的转换&#xff0c;比如>>右移、<<左移、&与等等&#xff0c;下面我们利用这些位运算来进行一个进制转换&#xff0c;将一个int整形&#xff08;32位&#xff09;十进制转二进制&#xff0c;以及其他的一些转换技巧。 一、十…

【SpringCloud10】OpenFeign服务接口调用

1.概述 1.1OpenFeign是什么 官网 Feign是一个声明式WebService客户端&#xff0c;使用Feign能让编写Web Service客户端更加简单。 它的使用方法是定义一个服务接口然后在上面添加注解&#xff0c;Feign也支持可拔插式的编码器和解码器&#xff0c;Spring Cloud对Feign进行了…

用详细实例说明和典型案例实现对分治法进行全面分析 | C++

第一篇 分治法 目录 第一篇 分治法 ●前言 ●一、分治法是什么&#xff1f; 1.简要介绍 2.生活实例 ●二、分治法的典型案例——硬币问题 1.具体问题 2.代码展示&#xff08;C&#xff09; 3.程序代码结果展示 ●总结 前言 简单的来说&#xff0c;算法就是用计算机程序代…

Docker学习笔记

容器本质上是一个线程&#xff0c;相当于从物理机中开辟了一个空间&#xff0c;专门给到某个程序使用 镜像的本质是一个软件源&#xff0c;这个软件源往往还带有它的环境变量、配置信息 docker是一个管理容器的平台工具 当运行容器时&#xff0c;使用的镜像如果在本地中不存…

PostgreSQL数据库FDW——Parquet S3 DefaultParquetReader类

S3RandomAccessFile S3RandomAccessFile类定义在parquet_s3_fdw.hpp&#xff0c;用于访问s3对象存储的类。其成员函数定义在parquet_s3_fdw.cpp文件中&#xff0c;S3RandomAccessFile构造函数用于初始化private成员(offset设置为0&#xff0c;isclosed设置为false)。 class S…

yolov5+车道线检测

目标检测与车道线检测在自动驾驶以及车辆定位中起着重要的辅助作用&#xff0c;是环境感知中不可缺少的一个部分。基于深度学习的车道线检测方法近年来也在不断的提升&#xff0c;比如论文&#xff1a;Ultra Fast Deep Lane Detection with HybridAnchor Driven Ordinal Classi…

[ 环境搭建篇 ] 安装 java 环境并配置环境变量(附 JDK1.8 安装包)

&#x1f36c; 博主介绍 &#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 _PowerShell &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 &#x1f389;点赞➕评论➕收藏 养成习…