Понимание концепции Lifetime Scope в Autofac

Простите меня, я только что выучил Autofac. У меня проблемы с пониманием Lifetime scope в 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>();
  }
}

Как указано в документе поставить. Lifetime scopes are disposable and they track component disposal.

Означает ли это, что service является одноразовым и может быть переработан GC после завершения оператора using(var scope = container.BeginLifetimeScope())?

И то же самое с anotherService во вложенной области? ?

Как я могу засвидетельствовать это каким-нибудь экспериментом?

Спасибо.


person Joe.wang    schedule 14.12.2016    source источник


Ответы (1)


Я думаю, вы должны сначала понять, что 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

Несколько замечаний, всегда помня о том, что все сервисы были разрешены 6 раз в 3 различных областях действия.

  • В итоге мы получили 6 экземпляров TransientService, что соответствует регистрации, которую мы сделали для контейнера. С точки зрения утилизации, каждый жизненный объем размещал свои 2 экземпляра, когда сам удалялся.

  • Было создано только 3 экземпляра LifetimeScopeService. В то время как каждая область жизненного цикла разрешала эту службу дважды, Autofac всегда возвращал в одной и той же области жизненного цикла один и тот же экземпляр при втором разрешении. Каждый экземпляр был удален владеющей областью жизни.

  • Во всем приложении был только 1 экземпляр SingletonService. Здесь нет границы области жизненного цикла, поскольку 3 области жизненного цикла разрешены для одного и того же экземпляра службы, который был удален при удалении корневой области.

Редактировать: отступ для вывода, чтобы сделать его более читабельным и сделать иерархию более четкой

person Mickaël Derriey    schedule 14.12.2016
comment
Извините, что опоздал. Это хорошо объяснено и хороший пример +1. очень ценится. Большое спасибо. - person Joe.wang; 16.07.2017
comment
@Mickael Derriey, сэр, хорошо ли объявить время жизни Transient, если у нас есть запрос на 100000 - person Saineshwar; 21.08.2019
comment
Не совсем понял, что вы имеете в виду, можете уточнить? - person Mickaël Derriey; 21.08.2019
comment
Спасибо. Мне нужно было проверить свое предположение о SingleInstance() при регистрации в дочерних областях, и это сэкономило мне массу времени. Если вы не возражаете, я разместил его на GitHub: github.com /rhyous/Autofac.Examples/tree/master/src/ - person Rhyous; 17.12.2019