Quartz.NET 3.0.3与Simple Injector构造函数注入实现方法
嘿,我刚好处理过类似的场景,Quartz.Net v3.x和Simple Injector的构造注入确实不能直接用默认的JobFactory,得自定义一个来衔接两者,给你一套可行的方案:
1. 实现Quartz自定义JobFactory
Quartz默认会自己实例化Job对象,所以我们需要替换成Simple Injector来创建实例,这样才能触发构造函数注入。创建一个实现IJobFactory的类:
using Quartz; using SimpleInjector; using System; public class SimpleInjectorJobFactory : IJobFactory { private readonly Container _container; public SimpleInjectorJobFactory(Container container) { _container = container ?? throw new ArgumentNullException(nameof(container)); } public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler) { // 为Job创建执行上下文Scope(如果Job依赖Scoped服务,比如DbContext,这一步很关键) var scope = _container.BeginExecutionContextScope(); try { // 让Simple Injector解析Job实例 var job = (IJob)scope.GetInstance(bundle.JobDetail.JobType); // 将Scope与Job绑定,方便后续释放 if (job is IScopedJob scopedJob) { scopedJob.Scope = scope; } return job; } catch { // 解析失败时释放Scope scope.Dispose(); throw; } } public void ReturnJob(IJob job) { // 释放Scope和Job资源 if (job is IScopedJob scopedJob) { scopedJob.Scope.Dispose(); } else if (job is IDisposable disposableJob) { disposableJob.Dispose(); } } } // 定义接口关联Job和Scope public interface IScopedJob : IJob, IDisposable { Scope Scope { get; set; } }
2. 注册Job和依赖到Simple Injector
不要直接注册IJob到JobWorker,而是注册具体的Job类(因为Quartz会根据具体类型请求实例),同时确保依赖项(比如日志)已正确注册:
var container = new Container(); // 注册日志依赖(替换成你实际的日志框架注册方式) container.Register<ILogger>(() => new LoggerImplementation(), Lifestyle.Singleton); // 注册你的JobWorker,生命周期按需选择Transient/Scoped container.Register<JobWorker>(Lifestyle.Transient); // 验证容器配置(提前发现注册问题) container.Verify();
3. 配置Quartz Scheduler使用自定义JobFactory
在创建Quartz调度器时,把我们的SimpleInjectorJobFactory设置进去:
using Quartz; using Quartz.Impl; using System.Threading.Tasks; // 初始化Quartz调度器工厂 var schedulerFactory = new StdSchedulerFactory(); var scheduler = await schedulerFactory.GetScheduler(); // 绑定自定义JobFactory scheduler.JobFactory = new SimpleInjectorJobFactory(container); // 定义Job和Trigger var jobDetail = JobBuilder.Create<JobWorker>() .WithIdentity("JobWorker", "DefaultGroup") .Build(); var trigger = TriggerBuilder.Create() .WithIdentity("JobWorkerTrigger", "DefaultGroup") .StartNow() .WithSimpleSchedule(x => x.WithIntervalInSeconds(10).RepeatForever()) .Build(); // 将Job和Trigger添加到调度器 await scheduler.ScheduleJob(jobDetail, trigger); // 启动调度器 await scheduler.Start();
4. 改造你的JobWorker实现
让JobWorker实现IScopedJob接口,接收Scope并正确释放资源,同时在构造函数中注入依赖:
public class JobWorker : IScopedJob { private readonly ILogger _logger; public Scope Scope { get; set; } // 构造函数注入日志依赖 public JobWorker(ILogger logger) { _logger = logger ?? throw new ArgumentNullException(nameof(logger)); } public async Task Execute(IJobExecutionContext context) { _logger.LogInformation("JobWorker执行于:{Time}", DateTime.Now); // 这里编写你的Job业务逻辑 await Task.CompletedTask; } public void Dispose() { // 释放Scope,同时释放Scope内的所有Scoped依赖 Scope?.Dispose(); } }
关键注意点
- 不要用
Container.Register<IJob, JobWorker>():Quartz创建Job时基于具体类型请求实例,直接注册具体类型才能让Simple Injector正确解析。 - Scope的处理:如果Job依赖Scoped生命周期服务(比如数据库上下文),一定要用
BeginExecutionContextScope创建Scope,避免依赖实例无法释放或重复使用。 - 容器验证:调用
container.Verify()能提前发现注册错误,避免运行时才暴露问题。
内容的提问来源于stack exchange,提问作者Darren
相关产品推荐
相关产品推荐

