1、通过NuGet引入Quartz
2、QuartzBackgroundService 需继承BackgroundService(当项目启动的时候,会进行调用,java也有许多这种内置的类,像beanFactory这些)
但是QuartzBackgroundService这个必须注册为本地服务类,如下
services.AddHostedService<QuartzBackgroundService>();//非常重要
详细代码:
public class QuartzBackgroundService : BackgroundService
{
private readonly IServiceProvider _serviceProvider;
public QuartzBackgroundService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
var scheduleService = _serviceProvider.GetService<QuartzConfigService>();
await scheduleService.init();
}
}
3、QuartzConfigService需实现IDisposable这个接口,该接口是c#中用来实现释放资源的,当程序关闭时,会调用Dispose()方法用来释放资源
详细代码:
public class QuartzConfigService : IDisposable
{
private readonly IScheduler _scheduler;
private readonly AppSettings _appSettings;
private readonly IServiceProvider _serviceProvider;
private readonly List<JobKey> jobKeys = new();
public QuartzConfigService(ISchedulerFactory schedulerFactory, QuartzJobFactory quartzJobFactory,
AppSettings appSettings, IServiceProvider serviceProvider)
{
_appSettings = appSettings;
_serviceProvider = serviceProvider;
_scheduler = schedulerFactory.GetScheduler().Result;
_scheduler.JobFactory = quartzJobFactory;
}
private IServiceScope getScope()
{
return _serviceProvider.CreateScope();
}
private List<QuartzJobConfig> getJobConfigs()
{
return _appSettings.jobConfigs;
}
/// <summary>
/// 初始化
/// </summary>
public async Task init()
{
string msg = "******init ScheduleService start******";
//获取配置
List<QuartzJobConfig> jobConfigs = getJobConfigs();
//获取临时有效的作用域
using var scope = getScope();
//扫描jobs
var jobTypes = scanJobTypes().ToList();
//未有jobs
if (jobTypes.Count == 0)
{
msg = "******init ScheduleService fail******:reason:no jobs";
return;
}
//启动任务调度
await _scheduler.Start();
//任务调度
await schedulingTasksConfig(jobTypes, jobConfigs);
msg = $"******init ScheduleService end******:total===>{jobKeys.Count}";
}
/// <summary>
/// 执行任务调度的配置初始化
/// </summary>
/// <param name="jobTypes"></param>
/// <param name="jobConfigs"></param>
private async Task schedulingTasksConfig(IEnumerable<Type> jobTypes, List<QuartzJobConfig> jobConfigs)
{
foreach (var jobType in jobTypes)
{
QuartzJobAttribute quartzJobAttribute = (QuartzJobAttribute) Attribute.GetCustomAttribute(jobType, typeof(QuartzJobAttribute));
string name = null;
JobKey jobKey = null;
string cron = null;
if (null == quartzJobAttribute)
{
//未使用注解 实现了IJob接口 采取默认配置方式
//获取类名
string className = jobType.Name;
}
else
{
string jobName = quartzJobAttribute.name;
//根据name匹配config
var scheduleJobConfig = jobConfigs.FirstOrDefault(c => c.name.Equals(jobName));
//scheduleJobConfig不为空且状态是未被禁用
if (scheduleJobConfig is {disabled: false})
{
name = scheduleJobConfig.name;
jobKey = JobKey.Create(name);
cron = scheduleJobConfig.cron;
await addJob(jobType, jobKey, cron);
}
}
}
}
/// <summary>
/// 扫描IJob的实现类
/// </summary>
/// <returns></returns>
private static IEnumerable<Type> scanJobTypes()
{
// 获取当前程序集
Assembly assembly = Assembly.GetExecutingAssembly();
//扫描IJob的子类
var jobTypes = assembly.GetTypes().Where(t => typeof(IJob).IsAssignableFrom(t)
&& t.IsClass
&& !t.IsAbstract);
return jobTypes;
}
/// <summary>
/// addJob
/// </summary>
/// <param name="jobType"></param>
/// <param name="jobKey"></param>
/// <param name="cron"></param>
private async Task addJob(Type jobType, JobKey jobKey, string cron)
{
string msg = $"add job:{jobKey.Group},{jobKey.Name}";
//IJobDetail是对任务的详细描述
IJobDetail jobDetail = JobBuilder.Create(jobType)
.WithIdentity(jobKey)
.Build();
//触发器
ITrigger trigger = TriggerBuilder.Create()
.WithIdentity(jobKey.Name)
.StartNow()
.WithCronSchedule(cron)
.Build();
//jobDetail与trigger绑定
await _scheduler.ScheduleJob(jobDetail, trigger);
//addToList
jobKeys.Add(jobKey);
}
/// <summary>
/// 程序结束 释放资源
/// </summary>
public async void Dispose()
{
foreach (var jobKey in jobKeys)
{
TriggerKey triggerKey = new TriggerKey(jobKey.Name, jobKey.Group);
await _scheduler.PauseJob(jobKey); // 停止触发器
await _scheduler.UnscheduleJob(triggerKey); // 移除触发器
string msg = $"delete job:{jobKey.Group},{jobKey.Name}";
await _scheduler.DeleteJob(jobKey); //删除任务
}
}
}
4、上面使用了扫描注解的方式,因此我们需要一个自定义注解,QuartzJobAttribute,详细代码:
/// <summary>
/// 在实现了IJob的子类上加上这个注解 为Jobs的任务名字
/// </summary>
public class QuartzJobAttribute : Attribute
{
public string name { get; set; }
public QuartzJobAttribute(string name)
{
this.name = name;
}
}
5、配置model类:QuartzJobConfig
public class QuartzJobConfig
{
/// <summary>
/// 任务名
/// </summary>
public string name { get; set; }
/// <summary>
/// cron表达式
/// </summary>
public string cron { get; set; }
/// <summary>
/// 任务状态:false未禁用 true禁用
/// </summary>
public bool disabled { get; set; }
}
6、超级重要,实现IJobFactory,防止实现了IJob类的服务类无法注入service对象,这是一个大坑,上代码:
/// <summary>
/// 手动实现Quartz定时器工厂 避免Jobs无法注入service的问题
/// </summary>
public class QuartzJobFactory : IJobFactory
{
/// <summary>
/// 服务提供器
/// </summary>
private readonly IServiceProvider _serviceProvider;
public QuartzJobFactory(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
}
public IJob NewJob(TriggerFiredBundle bundle, IScheduler scheduler)
{
IServiceScope serviceScope = _serviceProvider.CreateScope();
IJob job;
try
{
Type jobType = bundle.JobDetail.JobType;
job = (IJob) serviceScope.ServiceProvider.GetService(jobType);
}
catch
{
serviceScope.Dispose();
throw;
}
return job;
}
/// <summary>
/// 清理Quartz任务
/// </summary>
public void ReturnJob(IJob job)
{
if (job == null)
{
return;
}
IDisposable disposable = job as IDisposable;
disposable?.Dispose();
}
}
7、使用的方式超级简单:
(1)在实现了IJob的实现类上面加上注解[QuartzJob("任务名字")]
(2)appsettings.json加上这个配置,记得在AppSettings的这个大括号里面
"jobConfigs": [
{
"name": "任务名字",//必须和在实现类上添加注解的名字一摸一样 否则不会调度该任务
"cron": "", //cron表达式
"disabled": false//是否禁用
},
]
(3)在AppSettings.cs这个类中加入
public List<QuartzJobConfig> jobConfigs
{
get; set;
}
然后最后记得将有些类注入到Service中在stratUp类里面,注入这个东西,如果不懂就评论区问吧,累了,哈哈哈哈
本文介绍了如何在.NET应用中通过NuGet引入Quartz库进行任务调度,包括创建BackgroundService、实现IDisposable接口确保资源管理,以及自定义注解和配置模型。重点强调了IJobFactory的实现以解决服务注入问题。

1574

被折叠的 条评论
为什么被折叠?



