【问题标题】:Instantiating an object in a worker thread with Dependency Injection使用依赖注入在工作线程中实例化对象
【发布时间】:2018-05-02 14:49:20
【问题描述】:

我的目标是在并行线程中运行一个永无止境的进程。问题是,我不能只在新线程中实例化我的工作服务,因为我在我的应用程序中使用 DI。

根据我对 SO 的研究,我注意到很多人建议需要将抽象工厂注入线程中,以便在并行线程中动态实例化线程安全对象。 1, 2

/// <summary>
/// Responsible for starting parallel long running worker threads
/// </summary>
public class ParallelWorkerStarter
{
    private readonly IQueueProcessorFactory _queueProcessorFactory;

    public ParallelWorkerStarter(IQueueProcessorFactory queueProcessorFactory)
    {
        _queueProcessorFactory = queueProcessorFactory;
    }

    public void StartQueueProcessorThread()
    {    
        queueProcessor = new Thread(
        () =>
        {
            _queueProcessorFactory.Create().ProcessQueue();
        })
        { Name = "QueueProcessor" };
        queueProcessor.Start();
    }
}

IQueueProcessorFactory 的抽象工厂如下所示:

/// <summary>
/// Abstract factory responsible for producing an <see cref="IQueueProcessor"/>
/// </summary>
/// <remarks>
///  This abstract factory is used to generate an <see cref="IQueueProcessor"/> In a seperate thread. 
///  Therefore, all of its dependencies also need to be dynamically generated
/// </remarks>
public interface IQueueProcessorFactory
{
    /// <summary>
    /// Dynamically creates ab <see cref="IQueueProcessor"/>
    /// </summary>
    /// <returns>
    /// The <see cref="IQueueProcessor"/>.
    /// </returns>
    IQueueProcessor Create();
}

现在,我的主要问题是,实现 IQueueProcessor 的具体 QueueProcessor 有 11 个依赖项(我知道 SRP 代码味道),每个依赖项本身都有 5-6 个依赖项。

/// <inheritdoc />
public class QueueProcessorFactory : IQueueProcessorFactory
{
    private readonly IEventTriggerQueuedEventServiceFactory _qeueuedEventServiceFactory;

    private readonly ILoggerFactory _loggerFactory;

    private readonly IEventTriggerActionGroupLogServiceFactory _eventTriggerActionGroupLogServiceFactory;

    private readonly IExceptionLogServiceFactory _exceptionLogServiceFactory;

    private readonly IEventTriggerServiceFactory _eventTriggerServiceFactory;

    private readonly IConditionServiceFactory _conditionServiceFactory;

    private readonly IEventTriggerActionServiceFactory _eventTriggerActionServiceFactory;

    private readonly IEngineEnabledCheckerFactory _engineEnabledCheckerFactory;

    private readonly IEventTriggerScheduleSetServiceFactory _eventTriggerScheduleSetServiceFactory;

    private readonly IEventTriggerActionResultServiceFactory _eventTriggerActionResultServiceFactory;

    private readonly IWorkflowExceptionHandlerFactory _workflowExceptionHandlerFactory;

    public QueueProcessorFactory(
        IEventTriggerQueuedEventServiceFactory qeueuedEventServiceFactory,
        ILoggerFactory loggerFactory,
        IEventTriggerActionGroupLogServiceFactory eventTriggerActionGroupLogServiceFactory,
        IExceptionLogServiceFactory exceptionLogServiceFactory,
        IEventTriggerServiceFactory eventTriggerServiceFactory,
        IConditionServiceFactory conditionServiceFactory,
        IEventTriggerActionServiceFactory eventTriggerActionServiceFactory,
        IEngineEnabledCheckerFactory engineEnabledCheckerFactory,
        IEventTriggerScheduleSetServiceFactory eventTriggerScheduleSetServiceFactory,
        IEventTriggerActionResultServiceFactory eventTriggerActionResultServiceFactory,
        IWorkflowExceptionHandlerFactory workflowExceptionHandlerFactory)
    {
        _qeueuedEventServiceFactory = qeueuedEventServiceFactory;
        _loggerFactory = loggerFactory;
        _eventTriggerActionGroupLogServiceFactory = eventTriggerActionGroupLogServiceFactory;
        _exceptionLogServiceFactory = exceptionLogServiceFactory;
        _eventTriggerServiceFactory = eventTriggerServiceFactory;
        _conditionServiceFactory = conditionServiceFactory;
        _eventTriggerActionServiceFactory = eventTriggerActionServiceFactory;
        _engineEnabledCheckerFactory = engineEnabledCheckerFactory;
        _eventTriggerScheduleSetServiceFactory = eventTriggerScheduleSetServiceFactory;
        _eventTriggerActionResultServiceFactory = eventTriggerActionResultServiceFactory;
        _workflowExceptionHandlerFactory = workflowExceptionHandlerFactory;
    }

    /// <inheritdoc />
    public IQueueProcessor Create()
    {
        return new QueueProcessor(
            _qeueuedEventServiceFactory.Create(),
            _loggerFactory.Create(),
            _eventTriggerActionGroupLogServiceFactory.Create(),
            _exceptionLogServiceFactory.Create(),
            _eventTriggerServiceFactory.Create(),
            _conditionServiceFactory.Create(),
            _eventTriggerActionServiceFactory.Create(),
            _engineEnabledCheckerFactory.Create(),
            _eventTriggerScheduleSetServiceFactory.Create(),
            _eventTriggerActionResultServiceFactory.Create(),
            _workflowExceptionHandlerFactory.Create());
    }
}

这是否意味着我需要大约 60 多个抽象工厂才能在工作线程中实例化我的 IQueueProcessor?这听起来像是一场噩梦!有没有更好的方法或更有效的方法来实现这一点?

【问题讨论】:

  • 你使用哪个 IoC 框架?
  • 你的服务是线程安全的吗?
  • @arekzyla,这是我正在开发的内部库的一部分,因此它需要与容器无关。在我的测试消费者应用程序中,我使用的是 Unity,但它应该可以与其他容器一起使用。
  • @dymanoid 大多数不是。
  • @ShervinShahrdar 研究使依赖项线程安全可能是值得的。一般来说,依赖关系应该是无状态的......

标签: c# .net multithreading dependency-injection abstract-factory


【解决方案1】:

这是否意味着我需要大约 60 多个抽象工厂才能在工作线程中实例化我的 IQueueProcessor

最坏的情况,这可能是必需的。当所有依赖项都必须具有瞬态生命周期时,例如当它们不是线程安全的时,就会发生这种情况。

然而,在最佳情况中,所有这些依赖项都可能具有 Singleton 生命周期,这可能适用于线程安全依赖项。在这种情况下,没有个内部工厂是必需的:

public class QueueProcessorFactory : IQueueProcessorFactory
{
    private readonly IEventTriggerQueuedEventService _qeueuedEventService;    
    private readonly ILogger _logger;    
    private readonly IEventTriggerActionGroupLogService _eventTriggerActionGroupLogService;
    // etc...

    public QueueProcessorFactory(
        IEventTriggerQueuedEventService qeueuedEventService,
        ILogger logger,
        IEventTriggerActionGroupLogService eventTriggerActionGroupLogService,
        /* etc... */)
    {
        _qeueuedEventService = qeueuedEventService;
        _logger = logger;
        _eventTriggerActionGroupLogService = eventTriggerActionGroupLogService;
        // etc...
    }

    public IQueueProcessor Create()
    {
        return new QueueProcessor(
            _qeueuedEventService,
            _logger,
            _eventTriggerActionGroupLogService,
            /* etc... */);
    }
}

实际上,您可能需要将一些瞬态依赖项(需要工厂)与一些单例依赖项混合。

如果您最终需要几十个工厂,您可以考虑使用 DI Container。其中一些可以自动生成工厂接口的实现——您只需提供它们必须实现的接口。

此外,您不必为每个依赖项定义接口,但可以考虑使用通用接口,例如:

public interface IFactory<T>
{
    T Create();
}

同样,一些 DI 容器支持这样的工厂。您也可以考虑完全放弃接口,而只使用像 Func&lt;T&gt; 这样的委托。

不过,除非情况特殊,否则我不推荐 DI Container,而是支持 Pure DI。当你使用 DI 容器时,你会失去编译时的安全性,我倾向于认为这是不值得的。毕竟,编程的瓶颈很少是你的打字速度。

【讨论】:

  • IFactory 界面是天才,对我帮助很大!谢谢!
猜你喜欢
  • 1970-01-01
  • 2016-10-05
  • 2018-02-11
  • 1970-01-01
  • 1970-01-01
  • 2019-02-19
  • 2017-11-11
  • 2014-02-28
  • 1970-01-01
相关资源
最近更新 更多