【问题标题】:Ninject interception in multithreaded environment多线程环境下的 Ninject 拦截
【发布时间】:2014-10-18 08:29:30
【问题描述】:

我正在尝试使用 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,这样它就不会在调用之间共享?

【问题讨论】:

    标签: dependency-injection ninject ninject-interception


    【解决方案1】:

    这在多线程应用程序中应该可以正常工作,因为每个线程都应该有自己的对象图。因此,当您开始处理某些任务时,您首先要解析一个新图形,并且图形不应在线程之间传递。这允许将关于什么是线程安全(以及什么不是)的知识集中到应用程序中将所有内容连接起来的一个地方: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 原则正确应用到您的设计时,才能使用装饰器,因为您通常需要有一些明确的通用抽象才能将装饰器应用到你的系统。在遗留代码库中有效地使用装饰器可能会让人望而生畏。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-21
      • 2014-08-31
      • 1970-01-01
      相关资源
      最近更新 更多