2014-10-18 3 views
0

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

В однотридовой среде что-то вроде это работает:

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 из BeforeInvoke в AfterInvoke, чтобы он не делился между вызовами?

ответ

3

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

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

Это, однако, означает, что вы должны быть очень осторожны, когда вы вводите этот перехваченный компонент, потому что, если вы введете этот перехваченный объект в другой синглтон, у вас снова будут проблемы. Этот особый вид «проблемы» называется captive dependency a.k.a несовпадением образа жизни. Это действительно легко случайно неправильно сконфигурировать ваш контейнер, чтобы попасть в неприятности этим, и, к сожалению, 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 принципы дизайна, потому что вы часто должны иметь некоторые четкие общие абстракции, чтобы иметь возможность применить декоратор к большому диапазон классов в вашей системе. Мне может быть сложно использовать декораторы эффективно в устаревшей кодовой базе.