Quartz.Net系列(十六):通过Plugins模式使用Xml方式配置Job和Trigger和自定义LogPrivider
1.简单介绍
Quarz.Net中采用插件式来实现配置文件配置,通过XMLSchedulingDataProcessor类进行Xml数据处理
默认配置文件命名:quart_jobs.xml
public const string QuartzXmlFileName = "quartz_jobs.xml";
2.创建配置
首先安装扩展程序:Liquid XML Objects(基于XML的xsd文件创建数据模型)
新建quartz_jobs.xml文件,选择XML=>Schemas
Add
quartz_jobs.xml
<?xml version="1.0" encoding="utf-8" ?> <job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData"> <processing-directives> <overwrite-existing-data>true</overwrite-existing-data> </processing-directives> <schedule> <job> <name>myJob</name> <group>aaron</group> <description>这是Xml定义的Job</description> <job-type>Quartz_Demo.MyJob,Quartz_Demo</job-type> <durable>true</durable> <recover>true</recover> <job-data-map> <entry> <key>myKey</key> <value>myValue</value> </entry> </job-data-map> </job> <trigger> <simple> <name>myTrigger</name> <description>这是Xml定义的Trigger</description> <job-name>myJob</job-name> <job-group>aaron</job-group> <repeat-count>-1</repeat-count> <repeat-interval>1000</repeat-interval> </simple> </trigger> </schedule> </job-scheduling-data>
安装Quartz.Plugins包
编写代码
var assemblyName = typeof(Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin).AssemblyQualifiedName; var scheduler= await SchedulerBuilder.Create().UseXmlSchedulingConfiguration((options)=>{ options.SetProperty("quartz.plugin.xml.fileNames", "quartz_jobs.xml"); options.SetProperty("quartz.plugin.xml.scanInterval", "3"); options.SetProperty("quartz.threadPool.threadCount", "20"); }).Build(); //System.Collections.Specialized.NameValueCollection collection = new System.Collections.Specialized.NameValueCollection(); //collection.Add("quartz.plugin.xml.type", assemblyName); //collection.Add("quartz.plugin.xml.fileNames","quartz_jobs.xml"); //collection.Add("quartz.plugin.xml.scanInterval", "10"); //var factory = new StdSchedulerFactory(collection); //var scheduler = await factory.GetScheduler(); LogProvider.SetCurrentLogProvider(new ConsoleLogProvider()); await scheduler.Start(); var metaData=await scheduler.GetMetaData(); Console.WriteLine(metaData.ThreadPoolSize);
自定义LogPrivider
public class ConsoleLogProvider : ILogProvider { public Logger GetLogger(string name) { Logger loger = (logLevel, messageFunc, exception, formatParameters) => { if (logLevel >= LogLevel.Debug && messageFunc != null) { Console.WriteLine("[" + DateTime.Now.ToLongTimeString() + "] [" + logLevel + "] " + messageFunc(), formatParameters); } return true; }; return loger; } public IDisposable OpenMappedContext(string key, object value, bool destructure = false) { return null; } public IDisposable OpenNestedContext(string message) { return null; } }
运行图
源码解析
foreach (jobdetailType jobDetailType in jobNodes) { string jobName = jobDetailType.name.TrimEmptyToNull(); string jobGroup = jobDetailType.group.TrimEmptyToNull(); string jobDescription = jobDetailType.description.TrimEmptyToNull(); string jobTypeName = jobDetailType.jobtype.TrimEmptyToNull(); bool jobDurability = jobDetailType.durable; bool jobRecoveryRequested = jobDetailType.recover; Type jobType = TypeLoadHelper.LoadType(jobTypeName); IJobDetail jobDetail = JobBuilder.Create(jobType) .WithIdentity(jobName, jobGroup) .WithDescription(jobDescription) .StoreDurably(jobDurability) .RequestRecovery(jobRecoveryRequested) .Build(); if (jobDetailType.jobdatamap != null && jobDetailType.jobdatamap.entry != null) { foreach (entryType entry in jobDetailType.jobdatamap.entry) { string key = entry.key.TrimEmptyToNull(); string value = entry.value.TrimEmptyToNull(); jobDetail.JobDataMap.Add(key, value); } } if (Log.IsDebugEnabled()) { Log.Debug("Parsed job definition: " + jobDetail); } AddJobToSchedule(jobDetail); } // // Extract Trigger definitions... // List<triggerType> triggerEntries = new List<triggerType>(); if (data.schedule != null) { foreach (var schedule in data.schedule) { if (schedule != null && schedule.trigger != null) { triggerEntries.AddRange(schedule.trigger); } } } Log.Debug("Found " + triggerEntries.Count + " trigger definitions."); foreach (triggerType triggerNode in triggerEntries) { string triggerName = triggerNode.Item.name.TrimEmptyToNull(); string triggerGroup = triggerNode.Item.group.TrimEmptyToNull(); string triggerDescription = triggerNode.Item.description.TrimEmptyToNull(); string triggerCalendarRef = triggerNode.Item.calendarname.TrimEmptyToNull(); string triggerJobName = triggerNode.Item.jobname.TrimEmptyToNull(); string triggerJobGroup = triggerNode.Item.jobgroup.TrimEmptyToNull(); int triggerPriority = TriggerConstants.DefaultPriority; if (!triggerNode.Item.priority.IsNullOrWhiteSpace()) { triggerPriority = Convert.ToInt32(triggerNode.Item.priority); } DateTimeOffset triggerStartTime = SystemTime.UtcNow(); if (triggerNode.Item.Item != null) { if (triggerNode.Item.Item is DateTime time) { triggerStartTime = new DateTimeOffset(time); } else { triggerStartTime = triggerStartTime.AddSeconds(Convert.ToInt32(triggerNode.Item.Item)); } } DateTime? triggerEndTime = triggerNode.Item.endtimeSpecified ? triggerNode.Item.endtime : (DateTime?) null; IScheduleBuilder sched; if (triggerNode.Item is simpleTriggerType simpleTrigger) { string repeatCountString = simpleTrigger.repeatcount.TrimEmptyToNull(); string repeatIntervalString = simpleTrigger.repeatinterval.TrimEmptyToNull(); int repeatCount = ParseSimpleTriggerRepeatCount(repeatCountString); TimeSpan repeatInterval = repeatIntervalString == null ? TimeSpan.Zero : TimeSpan.FromMilliseconds(Convert.ToInt64(repeatIntervalString)); sched = SimpleScheduleBuilder.Create() .WithInterval(repeatInterval) .WithRepeatCount(repeatCount); if (!simpleTrigger.misfireinstruction.IsNullOrWhiteSpace()) { ((SimpleScheduleBuilder) sched).WithMisfireHandlingInstruction(ReadMisfireInstructionFromString(simpleTrigger.misfireinstruction)); } } else if (triggerNode.Item is cronTriggerType) { cronTriggerType cronTrigger = (cronTriggerType) triggerNode.Item; string cronExpression = cronTrigger.cronexpression.TrimEmptyToNull(); string timezoneString = cronTrigger.timezone.TrimEmptyToNull(); TimeZoneInfo tz = timezoneString != null ? TimeZoneUtil.FindTimeZoneById(timezoneString) : null; sched = CronScheduleBuilder.CronSchedule(cronExpression) .InTimeZone(tz); if (!cronTrigger.misfireinstruction.IsNullOrWhiteSpace()) { ((CronScheduleBuilder) sched).WithMisfireHandlingInstruction(ReadMisfireInstructionFromString(cronTrigger.misfireinstruction)); } } else if (triggerNode.Item is calendarIntervalTriggerType) { calendarIntervalTriggerType calendarIntervalTrigger = (calendarIntervalTriggerType) triggerNode.Item; string repeatIntervalString = calendarIntervalTrigger.repeatinterval.TrimEmptyToNull(); IntervalUnit intervalUnit = ParseDateIntervalTriggerIntervalUnit(calendarIntervalTrigger.repeatintervalunit.TrimEmptyToNull()); int repeatInterval = repeatIntervalString == null ? 0 : Convert.ToInt32(repeatIntervalString); sched = CalendarIntervalScheduleBuilder.Create() .WithInterval(repeatInterval, intervalUnit); if (!calendarIntervalTrigger.misfireinstruction.IsNullOrWhiteSpace()) { ((CalendarIntervalScheduleBuilder) sched).WithMisfireHandlingInstruction(ReadMisfireInstructionFromString(calendarIntervalTrigger.misfireinstruction)); } } else { throw new SchedulerConfigException("Unknown trigger type in XML configuration"); } IMutableTrigger trigger = (IMutableTrigger) TriggerBuilder.Create() .WithIdentity(triggerName, triggerGroup) .WithDescription(triggerDescription) .ForJob(triggerJobName, triggerJobGroup) .StartAt(triggerStartTime) .EndAt(triggerEndTime) .WithPriority(triggerPriority) .ModifiedByCalendar(triggerCalendarRef) .WithSchedule(sched) .Build(); if (triggerNode.Item.jobdatamap != null && triggerNode.Item.jobdatamap.entry != null) { foreach (entryType entry in triggerNode.Item.jobdatamap.entry) { string key = entry.key.TrimEmptyToNull(); string value = entry.value.TrimEmptyToNull(); trigger.JobDataMap.Add(key, value); } } if (Log.IsDebugEnabled()) { Log.Debug("Parsed trigger definition: " + trigger); } AddTriggerToSchedule(trigger); }