IoC之AutoFac(三)——生命周期

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

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

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

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

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

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

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

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

+---------------------------------------------------+
|                 Autofac Container                 |
|                Root Lifetime Scope                |
|                                                   |
| Logging Service | | ( 在所有请求中共享 ) | | | | +----------------------+ +----------------------+ | | | First Request Scope | | Second Request Scope | | | | | | | | | | Order Processor | | Order Processor | | | +----------------------+ +----------------------+ | +---------------------------------------------------+

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

三、实例周期范围

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

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

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

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

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

3.2  单个实例(SingleInstance)

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

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

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

using(var scope1 = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    var w1 = scope1.Resolve<Worker>();
    using(var scope2 = scope1.BeginLifetimeScope())
    {
      var w2 = scope2.Resolve<Worker>();
    }
  }
}

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

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

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

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

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

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

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

 1     using(var scope1 = container.BeginLifetimeScope("myscope"))
 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     }
12 
13     using(var scope3 = container.BeginLifetimeScope("myscope"))
14     {
15       for(var i = 0; i < 100; i++)
16       {
17         var w3 = scope3.Resolve<Worker>();
18         using(var scope4 = scope1.BeginLifetimeScope())
19         {
20           var w4 = scope4.Resolve<Worker>();
21         }
22       }
23     }

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

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

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

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

3.6  每个 Owned 一个实例 ( InstancePerOwned)

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

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

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

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

3.7 线程范围通过

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

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

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

   void ThreadStart()
    {
      using (var threadLifetime = container.BeginLifetimeScope())
      {
        var thisThreadsInstance = threadLifetime.Resolve<MyThreadScopedComponent>(); 
    }
  }

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

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

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

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

转载于:https://www.cnblogs.com/wyy1234/p/9140823.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值