了解 Autofac 中生命周期范围的概念
Understanding the concept of Lifetime scope in Autofac
我刚刚学习 Autofac
,我在理解 Autofac 生命周期范围 时遇到了一些问题。请帮助查看下面的代码。
using (var scope = container.BeginLifetimeScope())
{
// Resolve services from a scope that is a child
// of the root container.
var service = scope.Resolve<IService>();
// You can also create nested scopes...
using (var unitOfWorkScope = scope.BeginLifetimeScope())
{
var anotherService = unitOfWorkScope.Resolve<IOther>();
}
}
documentation 说:“生命周期范围是一次性的,它们跟踪组件处置”。
是不是说service
是一次性的,在using (var scope = container.BeginLifetimeScope())
语句结束后可以被GC回收?
嵌套范围内的 anotherService
也是如此吗?
如何测试?
谢谢。
我认为您首先必须了解 Autofac 允许注册具有不同生命周期的组件:
- 瞬态生命周期,通过
InstancePerDependency
,这意味着容器每次被要求解析组件时都会创建一个新实例
- 每个生命周期范围,通过
InstancePerLifetimeScope
,这意味着容器将解析为特定生命周期范围内组件的相同实例
- 单例,通过
SingleInstance
。在这种情况下,容器最多创建一个组件实例
那么组件处置轨迹是什么意思?
这意味着每个生命周期范围都会跟踪它拥有的组件。在处置生命周期范围后,每个拥有的组件都是一次性的 - 即实现 IDisposable
- 将被处置。
那么我的组件什么时候会被处理掉?
回到第一点,这取决于他们注册的生命周期。
如果组件注册了瞬态生命周期,所有实例将在释放拥有生命周期范围时被释放
如果它被注册为每个生命周期范围,那么一个实例将在拥有的生命周期范围被处置时被处置
如果组件已经注册为单例,则该实例属于根生命周期范围,只有在该根生命周期范围被释放时才会被释放
一些支持代码
public class TransientService : IDisposable
{
private static int _instanceCount = 0;
private readonly int _instanceNumber;
public TransientService()
{
_instanceCount++;
_instanceNumber = _instanceCount;
Console.WriteLine($"Just created TransientService #{_instanceNumber}");
}
public void Dispose()
{
Console.WriteLine($"Disposing TransientService #{_instanceNumber}");
}
}
public class LifetimeScopeService : IDisposable
{
private static int _instanceCount = 0;
private readonly int _instanceNumber;
public LifetimeScopeService()
{
_instanceCount++;
_instanceNumber = _instanceCount;
Console.WriteLine($"Just created LifetimeScopeService #{_instanceNumber}");
}
public void Dispose()
{
Console.WriteLine($"Disposing LifetimeScopeService #{_instanceNumber}");
}
}
public class SingletonService : IDisposable
{
private static int _instanceCount = 0;
private readonly int _instanceNumber;
public SingletonService()
{
_instanceCount++;
_instanceNumber = _instanceCount;
Console.WriteLine($"Just created SingletonService #{_instanceNumber}");
}
public void Dispose()
{
Console.WriteLine($"Disposing SingletonService #{_instanceNumber}");
}
}
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder
.RegisterType<TransientService>()
.AsSelf()
.InstancePerDependency();
builder
.RegisterType<LifetimeScopeService>()
.AsSelf()
.InstancePerLifetimeScope();
builder
.RegisterType<SingletonService>()
.AsSelf()
.SingleInstance();
using (var container = builder.Build())
{
Console.WriteLine("Created the root scope");
var rootTransientService = container.Resolve<TransientService>();
var rootLifetimeScopeService = container.Resolve<LifetimeScopeService>();
var rootSingletonService = container.Resolve<SingletonService>();
var rootTransientServiceTwo = container.Resolve<TransientService>();
var rootLifetimeScopeServiceTwo = container.Resolve<LifetimeScopeService>();
var rootSingletonServiceTwo = container.Resolve<SingletonService>();
using (var outerLifetimeScope = container.BeginLifetimeScope())
{
Console.WriteLine("Created the outer lifetime scope");
var outerTransientService = outerLifetimeScope.Resolve<TransientService>();
var outerLifetimeScopeService = outerLifetimeScope.Resolve<LifetimeScopeService>();
var outerSingletonService = outerLifetimeScope.Resolve<SingletonService>();
var outerTransientServiceTwo = outerLifetimeScope.Resolve<TransientService>();
var outerLifetimeScopeServiceTwo = outerLifetimeScope.Resolve<LifetimeScopeService>();
var outerSingletonServiceTwo = outerLifetimeScope.Resolve<SingletonService>();
using (var innerLifetimeScope = container.BeginLifetimeScope())
{
Console.WriteLine("Created the inner lifetime scope");
var innerTransientService = innerLifetimeScope.Resolve<TransientService>();
var innerLifetimeScopeService = innerLifetimeScope.Resolve<LifetimeScopeService>();
var innerSingletonService = innerLifetimeScope.Resolve<SingletonService>();
var innerTransientServiceTwo = innerLifetimeScope.Resolve<TransientService>();
var innerLifetimeScopeServiceTwo = innerLifetimeScope.Resolve<LifetimeScopeService>();
var innerSingletonServiceTwo = innerLifetimeScope.Resolve<SingletonService>();
}
Console.WriteLine("Disposed the inner lifetime scope");
}
Console.WriteLine("Disposed the outer lifetime scope");
}
Console.WriteLine("Disposed the root scope");
Console.ReadLine();
}
}
3 项服务,Autofac 支持的每个生命周期一项。程序很简单,我们有根生命周期作用域、外生命周期作用域和内生命周期作用域。
每个生命周期范围解析每个服务的 2 个实例,因此每个服务解析 6 次。
这是输出:
Created the root scope
Just created TransientService #1
Just created LifetimeScopeService #1
Just created SingletonService #1
Just created TransientService #2
Created the outer lifetime scope
Just created TransientService #3
Just created LifetimeScopeService #2
Just created TransientService #4
Created the inner lifetime scope
Just created TransientService #5
Just created LifetimeScopeService #3
Just created TransientService #6
Disposing TransientService #6
Disposing LifetimeScopeService #3
Disposing TransientService #5
Disposed the inner lifetime scope
Disposing TransientService #4
Disposing LifetimeScopeService #2
Disposing TransientService #3
Disposed the outer lifetime scope
Disposing TransientService #2
Disposing SingletonService #1
Disposing LifetimeScopeService #1
Disposing TransientService #1
Disposed the root scope
一些观察,始终牢记所有服务已通过 3 个不同的生命周期范围 6 次解析
我们最终得到了 TransientService
的 6 个实例,这与我们对容器进行的注册相匹配。在处置方面,每个生命周期范围在处置自身时处置了它们的 2 个实例。
只创建了 3 个 LifetimeScopeService
实例。虽然每个生命周期范围解析此服务两次,但 Autofac 总是在相同的生命周期范围内返回相同的实例,第二次解析。每个实例都由拥有的生命周期范围处理。
整个应用程序中只有 1 个 SingletonService
实例。此处没有生命周期范围边界,因为 3 个生命周期范围解析为同一个服务实例,该实例在根范围被释放时被释放。
编辑:缩进输出以使其更具可读性并使层次结构更清晰
我刚刚学习 Autofac
,我在理解 Autofac 生命周期范围 时遇到了一些问题。请帮助查看下面的代码。
using (var scope = container.BeginLifetimeScope())
{
// Resolve services from a scope that is a child
// of the root container.
var service = scope.Resolve<IService>();
// You can also create nested scopes...
using (var unitOfWorkScope = scope.BeginLifetimeScope())
{
var anotherService = unitOfWorkScope.Resolve<IOther>();
}
}
documentation 说:“生命周期范围是一次性的,它们跟踪组件处置”。
是不是说service
是一次性的,在using (var scope = container.BeginLifetimeScope())
语句结束后可以被GC回收?
嵌套范围内的 anotherService
也是如此吗?
如何测试?
谢谢。
我认为您首先必须了解 Autofac 允许注册具有不同生命周期的组件:
- 瞬态生命周期,通过
InstancePerDependency
,这意味着容器每次被要求解析组件时都会创建一个新实例 - 每个生命周期范围,通过
InstancePerLifetimeScope
,这意味着容器将解析为特定生命周期范围内组件的相同实例 - 单例,通过
SingleInstance
。在这种情况下,容器最多创建一个组件实例
那么组件处置轨迹是什么意思?
这意味着每个生命周期范围都会跟踪它拥有的组件。在处置生命周期范围后,每个拥有的组件都是一次性的 - 即实现 IDisposable
- 将被处置。
那么我的组件什么时候会被处理掉?
回到第一点,这取决于他们注册的生命周期。
如果组件注册了瞬态生命周期,所有实例将在释放拥有生命周期范围时被释放
如果它被注册为每个生命周期范围,那么一个实例将在拥有的生命周期范围被处置时被处置
如果组件已经注册为单例,则该实例属于根生命周期范围,只有在该根生命周期范围被释放时才会被释放
一些支持代码
public class TransientService : IDisposable
{
private static int _instanceCount = 0;
private readonly int _instanceNumber;
public TransientService()
{
_instanceCount++;
_instanceNumber = _instanceCount;
Console.WriteLine($"Just created TransientService #{_instanceNumber}");
}
public void Dispose()
{
Console.WriteLine($"Disposing TransientService #{_instanceNumber}");
}
}
public class LifetimeScopeService : IDisposable
{
private static int _instanceCount = 0;
private readonly int _instanceNumber;
public LifetimeScopeService()
{
_instanceCount++;
_instanceNumber = _instanceCount;
Console.WriteLine($"Just created LifetimeScopeService #{_instanceNumber}");
}
public void Dispose()
{
Console.WriteLine($"Disposing LifetimeScopeService #{_instanceNumber}");
}
}
public class SingletonService : IDisposable
{
private static int _instanceCount = 0;
private readonly int _instanceNumber;
public SingletonService()
{
_instanceCount++;
_instanceNumber = _instanceCount;
Console.WriteLine($"Just created SingletonService #{_instanceNumber}");
}
public void Dispose()
{
Console.WriteLine($"Disposing SingletonService #{_instanceNumber}");
}
}
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder
.RegisterType<TransientService>()
.AsSelf()
.InstancePerDependency();
builder
.RegisterType<LifetimeScopeService>()
.AsSelf()
.InstancePerLifetimeScope();
builder
.RegisterType<SingletonService>()
.AsSelf()
.SingleInstance();
using (var container = builder.Build())
{
Console.WriteLine("Created the root scope");
var rootTransientService = container.Resolve<TransientService>();
var rootLifetimeScopeService = container.Resolve<LifetimeScopeService>();
var rootSingletonService = container.Resolve<SingletonService>();
var rootTransientServiceTwo = container.Resolve<TransientService>();
var rootLifetimeScopeServiceTwo = container.Resolve<LifetimeScopeService>();
var rootSingletonServiceTwo = container.Resolve<SingletonService>();
using (var outerLifetimeScope = container.BeginLifetimeScope())
{
Console.WriteLine("Created the outer lifetime scope");
var outerTransientService = outerLifetimeScope.Resolve<TransientService>();
var outerLifetimeScopeService = outerLifetimeScope.Resolve<LifetimeScopeService>();
var outerSingletonService = outerLifetimeScope.Resolve<SingletonService>();
var outerTransientServiceTwo = outerLifetimeScope.Resolve<TransientService>();
var outerLifetimeScopeServiceTwo = outerLifetimeScope.Resolve<LifetimeScopeService>();
var outerSingletonServiceTwo = outerLifetimeScope.Resolve<SingletonService>();
using (var innerLifetimeScope = container.BeginLifetimeScope())
{
Console.WriteLine("Created the inner lifetime scope");
var innerTransientService = innerLifetimeScope.Resolve<TransientService>();
var innerLifetimeScopeService = innerLifetimeScope.Resolve<LifetimeScopeService>();
var innerSingletonService = innerLifetimeScope.Resolve<SingletonService>();
var innerTransientServiceTwo = innerLifetimeScope.Resolve<TransientService>();
var innerLifetimeScopeServiceTwo = innerLifetimeScope.Resolve<LifetimeScopeService>();
var innerSingletonServiceTwo = innerLifetimeScope.Resolve<SingletonService>();
}
Console.WriteLine("Disposed the inner lifetime scope");
}
Console.WriteLine("Disposed the outer lifetime scope");
}
Console.WriteLine("Disposed the root scope");
Console.ReadLine();
}
}
3 项服务,Autofac 支持的每个生命周期一项。程序很简单,我们有根生命周期作用域、外生命周期作用域和内生命周期作用域。
每个生命周期范围解析每个服务的 2 个实例,因此每个服务解析 6 次。 这是输出:
Created the root scope
Just created TransientService #1
Just created LifetimeScopeService #1
Just created SingletonService #1
Just created TransientService #2
Created the outer lifetime scope
Just created TransientService #3
Just created LifetimeScopeService #2
Just created TransientService #4
Created the inner lifetime scope
Just created TransientService #5
Just created LifetimeScopeService #3
Just created TransientService #6
Disposing TransientService #6
Disposing LifetimeScopeService #3
Disposing TransientService #5
Disposed the inner lifetime scope
Disposing TransientService #4
Disposing LifetimeScopeService #2
Disposing TransientService #3
Disposed the outer lifetime scope
Disposing TransientService #2
Disposing SingletonService #1
Disposing LifetimeScopeService #1
Disposing TransientService #1
Disposed the root scope
一些观察,始终牢记所有服务已通过 3 个不同的生命周期范围 6 次解析
我们最终得到了
TransientService
的 6 个实例,这与我们对容器进行的注册相匹配。在处置方面,每个生命周期范围在处置自身时处置了它们的 2 个实例。只创建了 3 个
LifetimeScopeService
实例。虽然每个生命周期范围解析此服务两次,但 Autofac 总是在相同的生命周期范围内返回相同的实例,第二次解析。每个实例都由拥有的生命周期范围处理。整个应用程序中只有 1 个
SingletonService
实例。此处没有生命周期范围边界,因为 3 个生命周期范围解析为同一个服务实例,该实例在根范围被释放时被释放。
编辑:缩进输出以使其更具可读性并使层次结构更清晰