了解 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 个生命周期范围解析为同一个服务实例,该实例在根范围被释放时被释放。

编辑:缩进输出以使其更具可读性并使层次结构更清晰