Autofac容器对象实例的几种生命周期类型

实例范围决定了如何在同一服务的请求之间共享实例。 请注意,您应该熟悉生命周期范围的概念,以便更好地理解此处发生的情况。

当请求服务时,Autofac可以返回单个实例(单实例作用域),新实例(每个依赖作用域)或某种上下文中的单个实例,例如 线程或HTTP请求(每个生命周期范围)。

这适用于从显式Resolve()调用返回的实例以及容器内部创建的实例,以满足另一个组件的依赖关系。

选择正确的生命周期范围将有助于避免组件寿命过长或不够长的俘获依赖和其他陷阱。 开发人员需要为每个应用程序组件做出正确的选择。

1.Instance Per Dependency

每次都会返回一个新的实例,并且这是默认的生命周期。

var builder = new ContainerBuilder();

// This...
builder.RegisterType<Worker>();

// 此句代码的效果同上
builder.RegisterType<Worker>().InstancePerDependency();

当您解析每个依赖项的实例组件时,每次都会得到一个新组件。

using(var scope = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    // Every one of the 100 Worker instances
    // resolved in this loop will be brand new.
    var w = scope.Resolve<Worker>();
    w.DoWork();
  }
}

2.Single Instance

单例,所有服务请求都将会返回同一个实例。

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

当您解析单个实例组件时,无论您请求何处,都始终获得相同的实例。

// It's generally not good to resolve things from the
// container directly, but for singleton demo purposes
// we do...
var root = container.Resolve<Worker>();

// We can resolve the worker from any level of nested
// lifetime scope, any number of times.
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>();

      // root, w1, and w2 are always literally the
      // same object instance. It doesn't matter
      // which lifetime scope it's resolved from
      // or how many times.
    }
  }
}

3.Instance Per Lifetime Scope

在一个嵌套语句块中,只会返回一个实例。

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

在解决每个生命周期实例作用域组件时,每个嵌套作用域将获得一个实例(例如,每个工作单元)。

using(var scope1 = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    // 每次从这里解析它
    // 你会得到相同的实例。
    var w1 = scope1.Resolve<Worker>();
  }
}

using(var scope2 = container.BeginLifetimeScope())
{
  for(var i = 0; i < 100; i++)
  {
    //每次从这里解析它
    //每次解析都会得到一个同样的实例,但是这个示例和上面的循环的实例不是同一个
    var w2 = scope2.Resolve<Worker>();
  }
}

4.Instance Per Matching Lifetime Scope

这与上面的'每个生命周期的实例范围'概念类似,但允许更精确地控制实例共享。

当您创建嵌套的生存期范围时,您可以“标记”或“命名”范围。具有每匹配生命周期范围的组件每个嵌套生命周期范围最多只有一个实例与给定名称匹配。这允许您创建一种“范围单例”,其中嵌套的生命周期范围可以在不声明全局共享实例的情况下共享某个组件的实例。

这对于特定于单个工作单元的对象是有用的,例如,一个HTTP请求,作为一个嵌套的生命周期可以创建每个工作单元。如果每个HTTP请求都创建一个嵌套的生命周期,那么每个具有每个生命周期范围的组件都将为每个HTTP请求创建一个实例。 (有关每个请求生命周期范围的更多信息。)

在大多数应用中,只有一层容器嵌套足以代表工作单元的范围。如果需要更多级别的嵌套(例如像global-> request-> transaction这样的东西),组件可以配置为使用标签在层次结构中的特定级别共享。

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

提供的标记值在启动时与生存期范围关联。 如果在没有正确命名的生命周期范围时尝试解析每个匹配生命周期范围的组件,则会得到一个异常。

//使用标签创建生命周期
using(var scope1 = container.BeginLifetimeScope("myrequest"))
{
  for(var i = 0; i < 100; i++)
  {
    var w1 = scope1.Resolve<Worker>();
    using(var scope2 = scope1.BeginLifetimeScope())
    {
      var w2 = scope2.Resolve<Worker>();

       // w1和w2始终是同一个对象
       //实例,因为该组件是每个匹配生命周期范围的,
       //所以它实际上是一个单例
       //命名范围
    }
  }
}

//使用标签创建另一个生命周期作用域
using(var scope3 = container.BeginLifetimeScope("myrequest"))
{
  for(var i = 0; i < 100; i++)
  {
    // w3 will be DIFFERENT than the worker resolved in the
    // earlier tagged lifetime scope.
    var w3 = scope3.Resolve<Worker>();
    using(var scope4 = scope3.BeginLifetimeScope())
    {
      var w4 = scope4.Resolve<Worker>();

       // w3和w4始终是同一个对象,因为
       //他们在相同的标记范围内,但他们是
       //与之前的w1,w2不一样。
    }
  }
}
//你无法解析每个匹配生命周期的组件
//如果没有匹配的范围。
using(var noTagScope = container.BeginLifetimeScope())
{
   //因为这个范围没有,所以抛出一个异常
   //有预期的标签,也没有任何父范围!
  var fail = noTagScope.Resolve<Worker>();
}

5.Instance Per Request

某些应用程序类型自然适用于“请求”类型语义,例如ASP.NET Web Forms和MVC应用程序。 在这些应用程序类型中,有能力为每个请求提供一种“单例”。

通过提供众所周知的生命周期范围标记,注册便利方法以及针对常见应用程序类型的集成,每个请求的实例基于每个匹配生命周期范围的实例构建。 但在幕后,它仍然只是每个匹配生命周期范围的实例。

这意味着如果您尝试解析注册为每个请求实例但没有当前请求的组件,那么您将得到一个异常。

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

6.Instance Per Owned

拥有的隐式关系类型创建新的嵌套生命周期作用域。 可以使用每个拥有实例的注册来将依赖关系限定到拥有的实例。

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

在这个例子中,ServiceForHandler服务将被限制在拥有的MessageHandler实例的生命周期中。

using(var scope = container.BeginLifetimeScope())
{
   //消息处理程序本身以及
   //解析依赖的ServiceForHandler服务
   //在一个小小的生命周期范围内
   // “范围。” 请注意解析一个拥有的<T>
   //表示您负责处理。
  var h1 = scope.Resolve<Owned<MessageHandler>>();
  h1.Dispose();
}

原文:http://autofaccn.readthedocs.io/en/latest/lifetime/instance-scope.html

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏唐郑望的专栏

Go 语言之三驾马车

Go 语言的三个核心设计: interface 、goroutine 、 channel。

1.7K0
来自专栏禁心尽力

解决springmvc在单纯返回一个字符串对象时所出现的乱码情况(极速版)

使用springmvc框架开发了这么长时间,之前都是直接返回jsp页面,乱码情况都是通过配置和手动编解码来解决,但是今天突然返回一段单纯的字符串时,发现中文乱码...

1879
来自专栏互联网杂技

express中app.use和app.get的区别及解析

写在前面:最近研究nodejs及其web框架express,对app.use和app.get没理解清,以致踩了坑浪费不少时间,我根据自己实践及总结出此博客,若有...

3416
来自专栏Java帮帮-微信公众号-技术文章全总结

05.HTML脚本/字符实体/URL/速查列表/

05.HTML脚本/字符实体/ URL/速查列表/ HTML 脚本 ---- JavaScript 使 HTML 页面具有更强的动态和交互性。 ---- HTM...

2854
来自专栏Golang语言社区

Go语言并发编程总结

Golang :不要通过共享内存来通信,而应该通过通信来共享内存。这句风靡在Go社区的话,说的就是 goroutine中的 channel ....... 他在...

2589
来自专栏PHP技术大全

通过代码审计找出网站中的XSS漏洞实战(三)

笔者此前录制了一套XSS的视频教程,在漏洞案例一节中讲解手工挖掘、工具挖掘、代码审计三部分内容,准备将内容用文章的形式再次写一此,前两篇已经写完,内容有一些关联...

982
来自专栏PHP技术大全

通过代码审计找出网站中的XSS漏洞实战(三)

笔者此前录制了一套XSS的视频教程,在漏洞案例一节中讲解手工挖掘、工具挖掘、代码审计三部分内容,准备将内容用文章的形式再次写一此,前两篇已经写完,内容有一些关联...

682
来自专栏ChaMd5安全团队

HBCTF第一场2个pwn题的简单分析

【ChaMd5安全团队所有文章均来源实战,为保证厂商安全信息,文章内容以思路为主。 需要转载,请先联系ChaMd5安全团队授权。 未经授权请勿转载。】...

42010
来自专栏我是业余自学C/C++的

汇编语言-第二章 寄存器(CPU工作原理)

1132
来自专栏令仔很忙

UML之状态图

  状态:是指在对象生命周期中满足某些条件、执行某些活动或等待某些事件的一个条件和状况。

531

扫码关注云+社区