阅读目录


一、Autofac中的生命周期相关概念

  服务的生命周期:是服务实例在您的应用程序中生存的时间 ,即从原始实例化到释放期间。例如,如果你“新建”了一个实现了IDisposable的对象,然后再调用Dispose(),那么这个对象的生命周期就是从你实例化的时候开始,被释放时结束(或者垃圾回收,如果你没有主动处置它)。

  服务范围:应用程序中可以与其他使用该服务的组件共享该服务的区域。例如,在你的应用程序中你可能有一个全局静态的单例 - 全局对象实例的“范围”将是整个应用程序。另一方面,您可以在使用全局单例的for循环中创建局部变量 - 局部变量的范围比全局范围小得多。

  Autofac中的生命周期概念:结合了这两个概念。生命周期的范围等同于您的应用程序中的一个工作单元。在解析服务问题时,Autofac跟踪已解析的一次性(IDisposable)组件,在工作单元结束时,您将释放关联的生命周期范围(scope),Autofac将自动清理/处理已解析的服务。

  生命周期管理的两件重要的事情就是共享和清理。

我们来看一个Web应用程序作为更具体的例子来说明生命周期范围的使用。 假设你有以下情况:

  1. 你有一个全局的单例日志记录服务。
  2. 两个并发请求进入Web应用程序。
  3. 每个请求都是一个逻辑的“工作单元”,每个请求都需要自己的订单处理服务。
  4. 每个订单处理服务都需要将日信息记录到日志服务中。

在这种情况下,您将拥有包含单例记录服务的根生存期范围,并且每个请求都有一个子生命周期范围,每个范围都有自己的订单处理服务:

  1. +---------------------------------------------------+
  2. | Autofac Container |
  3. | Root Lifetime Scope |
  4. | |
  5. | Logging Service |
  6. | ( 在所有请求中共享 ) |
  7. | |
  8. | +----------------------+ +----------------------+ |
  9. | | First Request Scope | | Second Request Scope | |
  10. | | | | | |
  11. | | Order Processor | | Order Processor | |
  12. | +----------------------+ +----------------------+ |
  13. +---------------------------------------------------+

When each request ends, the request lifetime scope ends and the respective order processor gets disposed. The logging service, as a singleton, stays alive for sharing by future requests. 
当每个请求结束时,请求生命周期范围(scope)被处理,相应的订单处理服务被销毁。 日志记录服务作为一个单例对象,在将来的请求中保持共享。

二、创建一个新的生命周期范围

您可以通过在任何现有生命周期作用域上从根容器开始调用BeginLifetimeScope()方法来创建生命周期作用域。生命周期作用域是可销毁的,他们跟踪组件的处置,所以确保你总是调用“Dispose()”或者把它们包装在“using”语句中。

  1. 1   using(var scope = container.BeginLifetimeScope())
  2. 2   {
  3. 3   //从作为根容器子项的作用域来解析服务
  4. 4   var service = scope.Resolve<IService>();
  5. 5
  6. 6   //您也可以创建嵌套的作用域...
  7. 7   using(var unitOfWorkScope = scope.BeginLifetimeScope())
  8. 8   {
  9. 9   var anotherService = unitOfWorkScope.Resolve<IOther>();
  10. 10   }
  11. 11   }

三、实例周期范围

3.1   每个依赖一个实例(InstancePerDependency)

  使用这个选项,每次请求服务都会返回一个新实例,这是默认选项

  1. var builder = new ContainerBuilder();
  2. builder.RegisterType<Worker>();
  3. builder.RegisterType<Worker>().InstancePerDependency();

  下面的代码,每次循环都生成一个新的实例,一共生成 100 个实例。

  1. 1   using(var scope = container.BeginLifetimeScope())
  2. 2   {
  3. 3    for(var i = 0; i < 100; i++)
  4. 4   {
  5. 5   //每次解析都获取一个新实例
  6. 6   var w = scope.Resolve<Worker>();
  7. 7   w.DoWork();
  8. 8   }
  9. 9   }

3.2  单个实例(SingleInstance)

  使用这个选项,在根范围或嵌套范围中请求服务,都返回同一个的实例。使用 SingleInstance() 指定。

  1. var builder = new ContainerBuilder();
  2. builder.RegisterType<Worker>().SingleInstance();

  下面的代码,w1 和 w2 始终是同一个对象,100 次循环只有一个 Worker 类的实例。

  1. using(var scope1 = container.BeginLifetimeScope())
  2. {
  3. for(var i = 0; i < 100; i++)
  4. {
  5. var w1 = scope1.Resolve<Worker>();
  6. using(var scope2 = scope1.BeginLifetimeScope())
  7. {
  8. var w2 = scope2.Resolve<Worker>();
  9. }
  10. }
  11. }

3.3  每个生命周期范围一个实例 (InstancePerLifetimeScope)

使用这个选项,在特定的 ILifetimeScope 中请求服务,只返回一个实例。下面的代码中,scope1 中的 100 次 w1 是同一个对象,scope2 中的 100 次 w2 是同一个对象,但是 w1 和 w2 不是同一个对象。

  1. 1   var builder = new ContainerBuilder();
  2. 2   builder.RegisterType<Worker>().InstancePerLifetimeScope();
  3. 3   using(var scope1 = container.BeginLifetimeScope())
  4. 4   {
  5. 5   for(var i = 0; i < 100; i++)
  6. 6   {
  7. 7   var w1 = scope1.Resolve<Worker>();
  8. 8   }
  9. 9   }
  10. 10
  11. 11   using(var scope2 = container.BeginLifetimeScope())
  12. 12   {
  13. 13   for(var i = 0; i < 100; i++)
  14. 14   {
  15. 15    var w2 = scope2.Resolve<Worker>();
  16. 16   }
  17. 17   }

3.4  每个匹配的生命周期范围一个实例(InstancePerMatchingLifetimeScope)

  类似于上面【每个生命周期范围一个实例】,但可以提供更多控制。使用此选项,允许为 ILifetimeScope 对象提供“标记”。在标记匹配的范围中只有一个实例。使用 InstancePerMatchingLifetimeScope() 方法指定。

  1. var builder = new ContainerBuilder();
  2. builder.RegisterType<Worker>().InstancePerMatchingLifetimeScope("myscope");

  下面的代码中,w1 和 w2 相同,w3 和 w4 相同,但 w1 和 w3 不同。

  1. 1 using(var scope1 = container.BeginLifetimeScope("myscope"))
  2. 2 {
  3. 3 for(var i = 0; i < 100; i++)
  4. 4 {
  5. 5 var w1 = scope1.Resolve<Worker>();
  6. 6 using(var scope2 = scope1.BeginLifetimeScope())
  7. 7 {
  8. 8 var w2 = scope2.Resolve<Worker>();
  9. 9 }
  10. 10 }
  11. 11 }
  12. 12
  13. 13 using(var scope3 = container.BeginLifetimeScope("myscope"))
  14. 14 {
  15. 15 for(var i = 0; i < 100; i++)
  16. 16 {
  17. 17 var w3 = scope3.Resolve<Worker>();
  18. 18 using(var scope4 = scope1.BeginLifetimeScope())
  19. 19 {
  20. 20 var w4 = scope4.Resolve<Worker>();
  21. 21 }
  22. 22 }
  23. 23 }

3.5  每个请求一个实例( InstancePerRequest)

  有些应用程序天然具有【请求】语义,例如 ASP.NET MVC 或 WebForm 应用程序。【每个请求一个实例】在【每个匹配的生命周期范围一个实例】基础上,通过提供范围标记,注册函数和常见类型集成实现。本质上是【每个匹配的生命周期范围一个实例】。

  1. var builder = new ContainerBuilder();
  2. builder.RegisterType<Worker>().InstancePerRequest();

ASP.NET Core 使用【每个生命周期范围一个实例】,而不是【每个请求一个实例】。

3.6  每个 Owned 一个实例 ( InstancePerOwned)

  Owned<T> 隐式关联类型创建嵌套的生命周期范围。使用 instance-per-owned 注册,可将依赖限定在 owned 实例中。

  1. var builder = new ContainerBuilder();
  2. builder.RegisterType<MessageHandler>();
  3. builder.RegisterType<ServiceForHandler>().InstancePerOwned<MessageHandler>();

  本例中 ServiceForHandler 服务会限制在 MessageHandler 实例范围内。

  1. using(var scope = container.BeginLifetimeScope())
  2. {
  3. // MessageHandler 和附属的 ServiceForHandler
  4. // 在 scope 下面的一个微型的 lifetime scope 中。
  5. // 解析 Owned<T> 需要程序员负责执行清理工作。
  6. var h1 = scope.Resolve<Owned<MessageHandler>>();
  7. h1.Dispose();
  8. }

3.7 线程范围通过

InstancePerLifetimeScope,每个线程建立自己的LifetimeScope

  1. var builder = new ContainerBuilder();
  2. builder.RegisterType<Service>()
  3. .InstancePerLifetimeScope();
  4. var container = builder.Build();

  然后让每个创建自己的 lifetime scope

  1.    void ThreadStart()
  2. {
  3. using (var threadLifetime = container.BeginLifetimeScope())
  4. {
  5. var thisThreadsInstance = threadLifetime.Resolve<MyThreadScopedComponent>();
        }
      }

重要:在多线程场景下,要小心不要将父范围清理掉。否则,派生线程中的子范围将无法解析服务。

  每个线程都将有自己的 MyThreadScopedComponent 实例,本质上是生命周期范围内的单例。范围内的实例不会提供到外部,因此很容易保持线程间的组件隔离。

  通过添加 ILifetimeScope 参数,可将父范围注入到生成线程的代码中,Autofac 会将当前范围自动注入,接下来可以使用它创建嵌套范围。

  1. 1 public class ThreadCreator
  2. 2 {
  3. 3 //把父范围注入生成线程的代码
  4. 4 private ILifetimeScope _parentScope;
  5. 5 public ThreadCreator(ILifetimeScope parentScope)
  6. 6 {
  7. 7 this._parentScope = parentScope;
  8. 8 }
  9. 9
  10. 10 public void ThreadStart()
  11. 11 {
  12. 12 using (var threadLifetime = this._parentScope.BeginLifetimeScope())
  13. 13 {
  14. 14 //开启一个线程时,在嵌套scope中解析,以此实现线程间组件的隔离
  15. 15 var thisThreadsInstance = threadLifetime.Resolve<MyThreadScopedComponent>();
  16. 16 }
  17. 17 }
  18. 18 }

参考文章:

1、https://blog.csdn.net/WuLex/article/details/78704903

2、http://www.yuanjiaocheng.net/Autofac/instance-scope.html

3、https://www.cnblogs.com/dongbeifeng/p/autofac-instance-scope.html

IoC之AutoFac(三)——生命周期的更多相关文章

  1. Spring源码学习笔记12——总结篇,IOC,Bean的生命周期,三大扩展点

    Spring源码学习笔记12--总结篇,IOC,Bean的生命周期,三大扩展点 参考了Spring 官网文档 https://docs.spring.io/spring-framework/docs/ ...

  2. autofac 实例生命周期

    转自逆心博客园 autofac 实例生命周期 实例生命周期决定在同一个服务的每个请求的实例是如何共享的. 当请求一个服务的时候,Autofac会返回一个单例 (single instance作用域), ...

  3. Autofac之生命周期和事件

    Autofac为注册的类型对象提供了一套生命周期事件,覆盖了一个类型从注册到最后“释放”的一套事件.有了这些事件,我们可以相对方便的在类型对象的各个阶段进行AOP操作. builder.Registe ...

  4. autofac 注入生命周期

    创建实例方法 1.InstancePerDependency 对每一个依赖或每一次调用创建一个新的唯一的实例.这也是默认的创建实例的方式. 官方文档解释:Configure the component ...

  5. Autofac实例生命周期

    1.默认,每次请求都会返回一个实例 builder.RegisterType<X>().InstancePerDependency(); 2.Per Lifetime Scope:这个作用 ...

  6. vue学习三:生命周期钩子

    生命周期钩子介绍: 每个 Vue 实例在被创建时都要经过一系列的初始化过程——例如,需要设置数据监听.编译模板.将实例挂载到 DOM 并在数据变化时更新 DOM 等.同时在这个过程中也会运行一些叫做生 ...

  7. Spring IOC -bean对象的生命周期详解

    生命周期执行的过程如下:1) spring对bean进行实例化,默认bean是单例2) spring对bean进行依赖注入3) 如果bean实现了BeanNameAware接口,spring将bean ...

  8. Docker 基本概念(三)-生命周期详解(镜像、容器、仓库)

    Docker三大组件:镜像.容器.仓库.  一.镜像 1 从仓库获取镜像 #一.从仓库获取镜像,帮助命令:docker pull -help 命令:docker pull [选项] [docker R ...

  9. autofac生命周期入门(如何避免内存泄漏)

    如果你是一个IOC新手,那么生命周期可能会比较难以理解.以至于谈到这个问题时,一些老手也时常表示疑虑和害怕.一个令人不安的问题就是-对象没有在合适的时机被销毁.这样一来内存的使用率就会一直攀升,直到程 ...

  10. Spring ( 三 ) Spring的Bean的装配与生命周期、专用测试

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 一.对象的生命周期 1.IOC之Bean的生命周期 创建带有生命周期方法的bean public cla ...

随机推荐

  1. TF:Tensorflow结构简单应用,随机生成100个数,利用Tensorflow训练使其逼近已知线性直线的效率和截距—Jason niu

    import os os.environ[' import tensorflow as tf import numpy as np x_data = np.random.rand(100).astyp ...

  2. Apache系列:Apache的全局配置

    配置文件组成: 整个配置文件由3段组成: (1)全局配置:对主服务器或虚拟机都有效,且有些功能是服务器自身工作属性: (2)主服务器:主站属性: (3)虚拟主机:虚拟主机及属性定义 注:第二段和第三段 ...

  3. Windows 自动启动 bat

    创建文件,然后把这个文件放到window开机自动执行的目录中,之后的每次开机都会重新启动这个脚本 cd /d %~dp0 %1 start "" mshta vbscript:cr ...

  4. 自定义sshd服务

    1.安装rsyslog服务和sshd服务并启动 2.配置日志文件    vim /etc/rsyslog.conf        在里面添加一行 local*.    /var/log/sshd.lo ...

  5. Alpha(4/10)

    鐵鍋燉腯鱻 项目:小鱼记账 团队成员 项目燃尽图 冲刺情况描述 站立式会议照片 各成员情况 团队成员 学号 姓名 git地址 博客地址 031602240 许郁杨 (组长) https://githu ...

  6. Win userAccountControl 基本属性

    userAccountControl 基本属性 属性标志 十六进制 十进制 说明 SCRIPT 0x0001 1 运行登录脚本 ACCOUNTDISABLE 0x0002 2 账户禁用 HOMEDIR ...

  7. 前缀和的应用 CodeForces - 932B Recursive Queries

    题目链接: https://vjudge.net/problem/1377985/origin 题目大意就是要你把一个数字拆开,然后相乘. 要求得数要小于9,否则递归下去. 这里用到一个递归函数: i ...

  8. [转]REMOTE_ADDR,HTTP_CLIENT_IP,HTTP_X_FORWARDED_FOR

    午睡一觉醒来,突然想伪造IP地址.搜了一下,Mark. 源地址:http://www.cnblogs.com/lmule/archive/2010/10/15/1852020.html ------- ...

  9. Codeforces.1051G.Distinctification(线段树合并 并查集)

    题目链接 \(Description\) 给定\(n\)个数对\(A_i,B_i\).你可以进行任意次以下两种操作: 选择一个位置\(i\),令\(A_i=A_i+1\),花费\(B_i\).必须存在 ...

  10. Stm32常见英文缩写

    Stm32常见英文缩写 https://wenku.baidu.com/view/4b9c2eee5022aaea998f0f5b.html STM32嵌入式开发常见缩写 https://wenku. ...