Перехват Ninject в многопоточной среде

Я пытаюсь создать перехватчик, используя Ninject.Extensions.Interception.DynamixProxy для регистрации времени завершения метода.

В однопоточной среде работает примерно так:

public class TimingInterceptor : SimpleInterceptor
{
    readonly Stopwatch _stopwatch = new Stopwatch();
    private bool _isStarted;


    protected override void BeforeInvoke(IInvocation invocation)
    {
        _stopwatch.Restart();
        if (_isStarted) throw new Exception("resetting stopwatch for another invocation => false results");
        _isStarted = true;
        invocation.Proceed();
    }

    protected override void AfterInvoke(IInvocation invocation)
    {
        Debug.WriteLine(_stopwatch.Elapsed);
        _isStarted = false;
    }
}

Однако в многопоточных сценариях это не сработает, поскольку StopWatch используется совместно между вызовами. Как передать экземпляр StopWatch из BeforeInvoke в AfterInvoke, чтобы он не делился между вызовами?


person neo112    schedule 18.10.2014    source источник


Ответы (1)


Это должно прекрасно работать в многопоточном приложении, потому что каждый поток должен получить свой собственный граф объектов. Поэтому, когда вы начинаете обрабатывать какую-то задачу, вы начинаете с разрешения нового графа, и графы не должны передаваться из потока в поток. Это позволяет централизованно хранить информацию о том, что является потокобезопасным (а что нет) в одном месте в приложении, которое связывает все: корень композиции.

Когда вы работаете таким образом, это означает, что когда вы используете этот перехватчик для мониторинга классов, которые являются одиночками (и используются между потоками), каждый поток по-прежнему будет получать свой собственный перехватчик (когда он зарегистрирован как переходный), потому что каждый раз, когда вы разрешаете, вы получаете новый перехватчик (даже если вы повторно используете один и тот же «перехваченный» экземпляр).

Это, однако, означает, что вы должны быть очень осторожны при внедрении этого перехваченного компонента, потому что, если вы внедрите этот перехваченный объект в другой синглтон, у вас снова будут проблемы. Этот особый вид «проблем» называется зависимостью, также известной как несоответствие образа жизни. . Очень легко случайно неправильно настроить контейнер, чтобы навлечь на себя неприятности, и, к сожалению, у Ninject нет возможности предупредить вас об этом.

Однако обратите внимание, что ваши проблемы исчезнут, если вы начнете использовать декораторы вместо перехватчиков, потому что с помощью декоратора вы можете хранить все в одном методе. Это означает, что даже декоратор может быть одноэлементным, не вызывая проблем с потоками. Пример:

// Timing cross-cutting concern for command handlers
public class TimingCommandHandlerDecorator<TCommand> : ICommandHandler<TCommand>
{
    private readonly ICommandHandler<TCommand> decoratee;

    public TimingCommandHandlerDecorator(ICommandHandler<TCommand> decoratee)
    {
        this.decoratee = decoratee;
    }

    public void Handle(TCommand command)
    {
        var stopwatch = Stopwatch.StartNew();
        this.decoratee.Handle(command);
        Debug.WriteLine(stopwatch.Elapsed);
    }
}

Конечно, использование декораторов часто возможно только в том случае, если вы правильно применили SOLID принципы вашего дизайна, потому что вам часто нужно иметь некоторые четкие общие абстракции, чтобы иметь возможность применять декораторы к большому количеству классов в вашей системе. Меня может пугать эффективное использование декораторов в базе устаревшего кода.

person Steven    schedule 18.10.2014