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

news2024/11/17 23:42:19

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官方文档进行深入了解。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/160241.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql-8.0.31-winx64详细安装教程

一、下载MySQL MySQL官网&#xff1a;https://www.mysql.com/cn/ mysql-8.0.31-winx64下载地址&#xff1a;https://dev.mysql.com/downloads/mysql/ 2、下载结束后&#xff0c;解压到指定目录&#xff0c;笔者存放在D盘 &#xff0c;为求简单&#xff0c;设置目录如下&#…

数据库历史数据年度备份

数据库历史数据年度备份 1、文件说明 matomo_backup.sql 备份库表结构脚本(这个根据自己数据结构准备&#xff0c;对于时间命名的表结构就不要加了&#xff0c;只加非时间命名的表结构) export.sh 数据导出脚本 clean.sh 源数据库历史数据清除脚本 2、需求与思路 需求 对…

怎么把PDF转换成图片?来看看这几个方法吧!

要说我们手机里最多的一种文件格式是什么&#xff1f;那应该就是图片了。相信在智能手机的时代&#xff0c;每个人手机里都会有至少几百上千张照片吧。毕竟有许多的事情我们都希望通过图片、照片的形式来记录下来。所以说如何将其他格式的文件变成图片格式就成了一个不大不小的…

开发那点事(十八)Vue开发PC桌面应用案例

写在前面的话 最近有在研究electron框架&#xff0c;踩了不少坑 &#xff0c;现在把这几天研究的成果分享给大家。 研究成果 vue项目打包成exe可安装程序pc应用版本升级&#xff08;需要配合oss服务器&#xff09; vue应用配置 路由文件base配置为空mode模式为默认的hashv…

智慧门户、信创门户、国产门户、数字化门户,如何构建出七大特色亮点?

作者&#xff1a;郑文平 概述 调研结果显示&#xff0c;世界500强企业100%建设了适合自己的集团门户管理系统&#xff0c;也叫作办公门户或内网门户&#xff0c;并通过统一门户最终提升各自整体的业务管理水平和流转效率&#xff0c;没有建设门户的公司面临如下制约&#xff…

二,Spring IOC以及整合mybatis

0 复习 工厂设计模式 工厂设计模式代替new方式创建对象&#xff0c;目的是解耦合。 Spring做为工厂的使用 applicationContext.xml配置bean标签 如何从工厂中获取对象 //创建工厂 ApplicationContext ctx new ClassPathXmlApplicationContext("classpath:applicationCont…

AWS实战:Aurora到Redshift数据同步

什么是AuroraAmazon Aurora是一种基于云且完全托管关系型数据库服务&#xff0c;与MySQL 和 PostgreSQL 数据库兼容&#xff0c;完全托管意味着自动对数据库进行管理&#xff0c;包括管理数据备份、硬件配置和软件更新等操作Amazon Aurora提供了企业级性能Amazon Aurora提供了多…

【C/C++】动态顺序表详解(附完整源码)

本章内容 写在前面 1.静态与动态是指什么&#xff1f; 2.动态顺序表结构的定义 3.动态顺序表的函数接口实现 4.动态顺序表的问题及思考 5.关于顺序表的OJ题 6.OJ答案及解析 1.移除元素 2.删除有序数组中的重复项 ​3.合并两个有序数组 7.动态顺序表完整源码 1.SeqL…

《mSystems》最新研究| 李香真老师亲临凌波微课LorMe云讲堂解读贡嘎山反硝化菌群组装模式和驱动因素

2021年11月2日&#xff0c;李香真团队在《mSystems》期刊正式发表了题为“Patterns and Drivers of nirK-Typeand nirS-Type Denitrifier Community Assembly along an Elevation Gradient”的研究论文。该研究以青藏高原东部边界最高山——贡嘎山作为研究平台&#xff0c;比较…

小程序与普通网页开发有什么区别?

小程序的开发同普通的网页开发相比有很大的相似性&#xff0c;小程序的主要开发语言也是 JavaScript&#xff0c;但是二者还是有些差别的。 普通网页开发可以使用各种浏览器提供的 DOM API&#xff0c;进行 DOM 操作&#xff0c;小程序的逻辑层和渲染层是分开的&#xff0c;逻…

[前端笔记] 1.WEB基本概念

[前端笔记] 1.WEB基本概念基本概念1.资源 resourse2.链接3.HTTP 协议4.网页的真实样子&#xff1a;HTML静态网页与动态网页1.静态网页2.动态网页现代网站架构1.网站架构当我们访问一个网站时&#xff0c;后台都会发生什么事情捏?www——万维网 www&#xff1a;World Wide Web …

JAVA中医舌诊接口使用示例代码,JAVA舌象图特征人工智能识别代码,JAVA实现舌象特征检测与识别

中医舌诊接口使用示例-Java示例项目 中医舌诊健康状态检测API 1&#xff0e;此文档适用于集成中国中医舌诊开放平台功能的用户。 2&#xff0e;此文档说明了与中国中医舌诊开放平台的数据交互方法&#xff08;restful接口&#xff09;&#xff0c;按需使用体质健康API、脏腑健…

盖子的c++小课堂——第十讲:字符

前言 我呢&#xff0c;早上刚发布第九讲&#xff0c;心里想的是马桶盖终于保住了&#xff0c;结果…… 生产队的刘同学&#xff1a;快&#xff0c;继续更&#xff0c;不然你下次吃泡面没调料包 其他粉丝&#xff1a;啊……啊对对对 啊&#xff01;&#xff01;&#xff01;&…

OPTEE TA介绍

前言 本文主要介绍OPTEE的TA(Trusted Applications)&#xff0c;翻译自官方文档&#xff1a;Trusted Applications — OP-TEE documentation documentation (optee.readthedocs.io) 有两种方法可以实现可信应用程序 &#xff08;TA&#xff09;&#xff1a;伪 TA 和用户模式 T…

Speedoffice(word)如何输入特殊符号?

Word文档有时需要输入人民币单位“元”&#xff08;&#xff09;的符号&#xff0c;那么怎么打出来了&#xff0c;以我最常用的Speedoffice为例和大家分享一下方法。步骤&#xff1a;1&#xff0c;首先运行office软件&#xff0c;新建一份word&#xff0c;找到“插入”菜单栏里…

再学C语言33:函数——地址运算符

C中最重要、最复杂的概念之一就是指针&#xff08;pointer&#xff09; 指针是用于存储地址的变量 例如&#xff1a;scanf()函数中使用地址作为参数 当需要改变调用函数中的某个值时&#xff0c;任何被调用的无返回值的C函数都需要使用地址参数完成该任务 一、地址运算符&a…

c语言重点

1、以下代码循环几次&#xff1f;&#xff08;面试题&#xff09; void test(){int i; // 局部变量 i 的值是不确定的for(;i<10;i){;} }答案是---------不确定&#xff0c;在 c 语言中局部变量 i 没有初始化&#xff0c;值是不确定的&#xff0c;所以 i 的值可能是…

GeoHash 的编码方法

对一组经纬度进行 GeoHash 编码时&#xff0c;我们要先对经度和纬度分别编码&#xff0c;然后再把经纬度各自的编码组合成一个最终编码。 对于一个地理位置信息来说&#xff0c;它的经度范围是[-180,180]。GeoHash 编码会把一个经度值编码成一个 N 位的二进制值&#xff0c;我…

MySQL进阶篇之存储引擎

01、存储引擎 1.1、MySQL体系结构 连接层 最上层是一些客户端和链接服务&#xff0c;主要完成一些类似于连接处理、授权认证、及相关的安全方案。服务器也会为安全接入的每个客户端验证它所具有的操作权限。 服务层 第二层架构主要完成大多数的核心服务功能&#xff0c;如SQL…

重要的字符(串)函数的使用及其实现

目录 字符串函数注意点 1、\0 2、适当使用const修饰 3、多使用assert断言 4、库函数不可能完全安全 1、求字符串长度strlen 1、计数实现 2、递归实现 3、指针相减求元素个数 2、长度不受限制的字符串函数 1、strcpy 2、strcat 3、strcmp 3、长度受限制的字符串函数…