[关闭]
@muyanfeixiang 2016-01-18T14:53:41.000000Z 字数 8272 阅读 4285

控制作用域和生命周期(Scope and Lifetime)

Autofac


Lifetime Scopes

创建Lifetme Scopes

手动创建作用域,并Disposal。
Lifetime scopes are disposable and they track component disposal, so make sure you always call “Dispose()”or wrap them in “using” statements.
using(var scope = container.BeginLifetimeScope())
{
// Resolve services from a scope that is a child
// of the root container.
var service = scope.Resolve();

// You can also create nested scopes...
using(var unitOfWorkScope = scope.BeginLifetimeScope())
{
var anotherService = unitOfWorkScope.Resolve();
}
}

给Lifetime Scopes打标签

有时候你可能需要在Unit of work内共享一些服务,但是由不希望采用全局的共享便利,如单例模式。例如web应用的per-request生命周期,在这中情况下你可以使用InstancePerMatchingLifetimeScope来标识你的生命周期和服务。

举例如下,有个发邮件的组件,事务逻辑中需要发送多次邮件,所以可以在每个逻辑事务片中共享邮件服务。然后不希望邮件组件成为全局单例,可以如下设置。

  1. // Register your transaction-level shared component
  2. // as InstancePerMatchingLifetimeScope and give it
  3. // a "known tag" that you'll use when starting new
  4. // transactions.
  5. var builder = new ContainerBuilder();
  6. builder.RegisterType<EmailSender>()
  7. .As<IEmailSender>()
  8. .InstancePerMatchingLifetimeScope("transaction");
  9. // Both the order processor and the receipt manager
  10. // need to send email notifications.
  11. builder.RegisterType<OrderProcessor>()
  12. .As<IOrderProcessor>();
  13. builder.RegisterType<ReceiptManager>()
  14. .As<IReceiptManager>();
  15. var container = builder.Build();
  16. // Create transaction scopes with a tag.
  17. using(var transactionScope = container.BeginLifetimeScope("transaction"))
  18. {
  19. using(var orderScope = transactionScope.BeginLifetimeScope())
  20. {
  21. // This would resolve an IEmailSender to use, but the
  22. // IEmailSender would "live" in the parent transaction
  23. // scope and be shared across any children of the
  24. // transaction scope because of that tag.
  25. var op = orderScope.Resolve<IOrderProcessor>();
  26. op.ProcessOrder();
  27. }
  28. using(var receiptScope = transactionScope.BeginLifetimeScope())
  29. {
  30. // This would also resolve an IEmailSender to use, but it
  31. // would find the existing IEmailSender in the parent
  32. // scope and use that. It'd be the same instance used
  33. // by the order processor.
  34. var rm = receiptScope.Resolve<IReceiptManager>();
  35. rm.SendReceipt();
  36. }
  37. }

Adding Registrations to a Lifetime Scope

Autofac 允许你在创建生命周期时添加“on the fly”。This can help you when you need to do a sort of “spot weld” limited registration override or if you generally just need some additional stuff in a scope that you don’t want to register globally. You do this by passing a lambda to BeginLifetimeScope() that takes a ContainerBuilder and adds registrations.(在创建生命周期时,注册额外的服务,而不需要全局注册)

  1. using(var scope = container.BeginLifetimeScope(
  2. builder =>
  3. {
  4. builder.RegisterType<Override>().As<IService>();
  5. builder.RegisterModule<MyModule>();
  6. }))
  7. {
  8. // The additional registrations will be available
  9. // only in this lifetime scope.
  10. }

实例范围(Instance Scope)

实例范围决定了一个实例在request之间怎么共享的。
当请求一个服务时,autofac可以返回单例(single instance scope),新的实例(per dependency scope),或者某种上下文的单例,如线程或者http请求(per lifetime scope)。
This applies to instances returned from an explicit Resolve() call as well as instances created internally by the container to satisfy the dependencies of another component.

Instance Per Dependency

在别的容器中也叫transient’ or ‘factory’,在每次请求服务时都会返回一个独一无二的实例。
如果没有指定的生命周期,这是默认行为。

  1. var builder = new ContainerBuilder();
  2. // This...
  3. builder.RegisterType<Worker>();
  4. // ...is the same as this:
  5. builder.RegisterType<Worker>().InstancePerDependency();

每一Resolve依赖时,都返回一个新的组件。

  1. using(var scope = container.BeginLifetimeScope())
  2. {
  3. for(var i = 0; i < 100; i++)
  4. {
  5. // Every one of the 100 Worker instances
  6. // resolved in this loop will be brand new.
  7. var w = scope.Resolve<Worker>();
  8. w.DoWork();
  9. }
  10. }

Single Instance

在所有请求和嵌套作用域内都会返回同一个实例。

  1. var builder = new ContainerBuilder();
  2. builder.RegisterType<Worker>().SingleInstance();
  1. // It's generally not good to resolve things from the
  2. // container directly, but for singleton demo purposes
  3. // we do...
  4. var root = container.Resolve<Worker>();
  5. // We can resolve the worker from any level of nested
  6. // lifetime scope, any number of times.
  7. using(var scope1 = container.BeginLifetimeScope())
  8. {
  9. for(var i = 0; i < 100; i++)
  10. {
  11. var w1 = scope1.Resolve<Worker>();
  12. using(var scope2 = scope1.BeginLifetimeScope())
  13. {
  14. var w2 = scope2.Resolve<Worker>();
  15. // root, w1, and w2 are always literally the
  16. // same object instance. It doesn't matter
  17. // which lifetime scope it's resolved from
  18. // or how many times.
  19. }
  20. }
  21. }

Instance Per Lifetime Scope

这个作用域可以应用于嵌套作用域。per-lifetime scope组件在嵌套的作用域内最多有一个实例。
This is useful for objects specific to a single unit of work that may need to nest additional logical units of work. Each nested lifetime scope will get a new instance of the registered dependency.

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

当你解析per lifetime scope实例组件时,在每个嵌套的作用域(e.g. per unit of work),只有一个实例。

  1. using(var scope1 = container.BeginLifetimeScope())
  2. {
  3. for(var i = 0; i < 100; i++)
  4. {
  5. // Every time you resolve this from within this
  6. // scope you'll get the same instance.
  7. var w1 = scope1.Resolve<Worker>();
  8. }
  9. }
  10. using(var scope2 = container.BeginLifetimeScope())
  11. {
  12. for(var i = 0; i < 100; i++)
  13. {
  14. // Every time you resolve this from within this
  15. // scope you'll get the same instance, but this
  16. // instance is DIFFERENT than the one that was
  17. // used in the above scope. New scope = new instance.
  18. var w2 = scope2.Resolve<Worker>();
  19. }
  20. }

Instance Per Matching Lifetime Scope

这个与Instance Per Lifetime Scope类似,但是可以用更精确的实例共享控制。
当创建嵌套生命周期时,可以给该周期打上“标签”或者“名字”。A component with per-matching-lifetime scope will have at most a single instance per nested lifetime scope that matches a given name。这样可以创建scoped singleton,其中的嵌套周期就可以共享组件,而不需要创建全局的实例。

对单个unit of work很有用,如http请求,作为嵌套生命周期来创建。 If a nested lifetime is created per HTTP request, then any component with per-lifetime scope will have an instance per HTTP request. (More on per-request lifetime scope below.)

在大部分应用中,只需要一个层级的容器嵌套就可以代表unit of work。如果需要多个嵌套层级(如global->request->transaction),组件可以通过tag来创建在特定层级共享。

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

当开始一个嵌套生命周期时,tag就和该生命周期关联。You will get an exception if you try to resolve a per-matching-lifetime-scope component when there’s no correctly named lifetime scope.(如果解析不存的tag标识的生命周期,会出异常)。

  1. // Create the lifetime scope using the tag.
  2. using(var scope1 = container.BeginLifetimeScope("myrequest"))
  3. {
  4. for(var i = 0; i < 100; i++)
  5. {
  6. var w1 = scope1.Resolve<Worker>();
  7. using(var scope2 = scope1.BeginLifetimeScope())
  8. {
  9. var w2 = scope2.Resolve<Worker>();
  10. // w1 and w2 are always the same object
  11. // instance because the component is per-matching-lifetime-scope,
  12. // so it's effectively a singleton within the
  13. // named scope.
  14. }
  15. }
  16. }
  17. // Create another lifetime scope using the tag.
  18. using(var scope3 = container.BeginLifetimeScope("myrequest"))
  19. {
  20. for(var i = 0; i < 100; i++)
  21. {
  22. // w3 will be DIFFERENT than the worker resolved in the
  23. // earlier tagged lifetime scope.
  24. var w3 = scope3.Resolve<Worker>();
  25. using(var scope4 = scope1.BeginLifetimeScope())
  26. {
  27. var w4 = scope4.Resolve<Worker>();
  28. // w3 and w4 are always the same object because
  29. // they're in the same tagged scope, but they are
  30. // NOT the same as the earlier workers (w1, w2).
  31. }
  32. }
  33. }
  34. // You can't resolve a per-matching-lifetime-scope component
  35. // if there's no matching scope.
  36. using(var noTagScope = container.BeginLifetimeScope())
  37. {
  38. // This throws an exception because this scope doesn't
  39. // have the expected tag and neither does any parent scope!
  40. var fail = noTagScope.Resolve<Worker>();
  41. }

Instance Per Request

一些应用类型自然的拥有“request”类型语义,如ASP.NET MVC。在这些应用类型中,拥有某种形式的“singleton per request”是很有帮助的。Instance per request builds on top of instance per matching lifetime scope by providing a well-known lifetime scope tag, a registration convenience method, and integration for common application types(每次请求获取一个实例,是通过提供一个well-known的生命周期tag,a registration convenience method, and integration for common application types来构建在per matching lifetime scope之上的). 本质上就是per matching lifetime scope。

这意味这如果没有当前请求,而你却去解析一个基于instance-per-request注册的组件时,就会抛出异常。
There is a detailed FAQ outlining how to work with per-request lifetimes.

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

Instance Per Owned

Owned隐式的关系类型,创建了新的嵌套生命周期。可以通过 instance-per-owned注册,可以将依赖范围限制在宿主实例中。

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

在这个例子中,ServiceForHandler服务的的生命周期限制在宿主MessageHandler实例的生命周期中(In this example the ServiceForHandler service will be scoped to the lifetime of the owned MessageHandler instance.)。

  1. using(var scope = container.BeginLifetimeScope())
  2. {
  3. // The message handler itself as well as the
  4. // resolved dependent ServiceForHandler service
  5. // is in a tiny child lifetime scope under
  6. // "scope." Note that resolving an Owned<T>
  7. // means YOU are responsible for disposal.
  8. var h1 = scope.Resolve<Owned<MessageHandler>>();
  9. h1.Dispose();//要释放资源
  10. }

Thread Scope

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注