4

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

 2 years ago
source link: https://segmentfault.com/a/1190000040518293
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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

发布于 8 月 15 日

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

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

遇到的问题

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

image.png

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

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

image.png

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

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

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

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

image.png

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

image.png

解决的办法

  •        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

image.png

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK