记Quartz中使用AutoFac依赖注入遇到的问题

背景

       最近在做一个需求,就是在Job中捕捉异常,然后通过邮件或者消息的方式推送给指定人员,在需求实现的过程中遇到的一个注入问题,觉得很有意思,特此记录。

       如果您看了觉得或者已经有更好的办法,烦请告诉我一下,我们可以共同讨论,如果有地方不对,也请不吝斧正。

遇到的问题

       由于不同功能的Job很多,每一个Job中都要实现对发生异常的消息发送,现有的Job是这样的

记Quartz中使用AutoFac依赖注入遇到的问题_第1张图片

       为了实现这个需求,也为了以后更好的维护,我准备用事件委托的模式去实现,将对异常消息发送的业务逻辑拆出,保证职责单一,思路如下:


    1. 在Job和IJob中间再加一层IExceptionJobHandler接口作为约束
    2. 接口中定义一个发送异常消息的事件PushException
    3. 然后每一个Job在异常时去触发这个事件,外部只需要统一订阅一个事件即可。

记Quartz中使用AutoFac依赖注入遇到的问题_第2张图片

       到目前这一步是可行的,虽然不是很完美的设计,但是还是比较清晰的,但是另外一个问题来了,我如何通过Autofac注入这个Job呢,原来直接继承自Ijob现在加了一层。

问题分析

       这个问题花了我整整大约4个小时的时间去研究依赖注入的方式还在网上搜了好久,没什么进展,然后重新梳理了一下框架依赖注入的代码,发现是走错路了,注入Job使用的是Autofac.Extras.Quartz来完成的,这下知道方向了。

 var builder = new ContainerBuilder();
 builder.RegisterModule(new QuartzAutofacFactoryModule
 {
     ConfigurationProvider = c => schedulerConfig
 });

       这个QuartzAutofacFactoryModule里面一定有我想知道的东西,就在Github上下载了Autofac.Extras.Quartz的源码,打开一看,果然发现了它的真面目

记Quartz中使用AutoFac依赖注入遇到的问题_第3张图片

       这里面就是对Job依赖注入的,但是没有发现对Job的注册和构建,注意箭头标记的,它有一个AutofacJobFactory类,接收一个ILifetimeScope,而它的作用就是用来构建Job为作用域周期生效的服务实例。

记Quartz中使用AutoFac依赖注入遇到的问题_第4张图片

解决的办法

  •        1.上面以及分析出构建Job服务实例的,是一个叫AutofacJobFactory的工厂,返回一个IJob,那如何把IExceptionJobHandler注入进去,让我们Job实例拥有这个事件呢?
  •        2.因为我们的IExceptionJobHandler已经继承了IJob,也就是说这里直接可以把Ijob换成IExceptionJobHandler,那该如何实现呢?

继承

  •        3.我们观察到在AutofacJobFactory构建服务的方法是一个虚方法,所以利用继承我们新建一个ExtendAutofacJobFactory来重写它将Ijob换成IExceptionJobHandler
public class ExtendAutofacJobFactory : AutofacJobFactory
  {
     protected override IJob ResolveJobInstance(ILifetimeScope nestedScope, IJobDetail jobDetail)
       {
            //验证Job是否派生自IExceptionJobHandler
            if (typeof(IExceptionJobHandler).IsAssignableFrom(jobDetail.JobType))
            {
                IExceptionJobHandler instance = null;
                instance = (IExceptionJobHandler)CreateIJob(nestedScope, jobDetail);
                //注册事件统一处理入口
                instance.PushException += pushExceptionMessageManager.Value.ExceptionJobHandler
                    return instance;
            }
            else
            {
                return base.ResolveJobInstance(nestedScope, jobDetail);
            }

       }
  }
  •        4.我们需要把重写的构造工厂放入QuartzAutofacFactoryModule,依然选择继承的方式去重写QuartzAutofacFactoryModule,然后在加载服务时将服务构造工厂换成我们自己的ExtendAutofacJobFactory

记Quartz中使用AutoFac依赖注入遇到的问题_第5张图片

  •        5. 在Autofac注册服务地方将QuartzAutofacFactoryModule改为ExtendQuartzAutofacFactoryModule,至此完成了自定义注入。
builder.RegisterModule(new ExtendQuartzAutofacFactoryModule
{
    ConfigurationProvider = c => schedulerConfig
});

你可能感兴趣的:(记Quartz中使用AutoFac依赖注入遇到的问题)