zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    HDU 6071
    HDU 6073
    HDU 2124 Repair the Wall(贪心)
    HDU 2037 今年暑假不AC(贪心)
    HDU 1257 最少拦截系统(贪心)
    HDU 1789 Doing Homework again(贪心)
    HDU 1009 FatMouse' Trade(贪心)
    HDU 2216 Game III(BFS)
    HDU 1509 Windows Message Queue(队列)
    HDU 1081 To The Max(动态规划)
  • 原文地址:https://www.cnblogs.com/Alex80/p/10703107.html
Copyright © 2011-2022 走看看