Quartz.Net调度框架配置解析
在平时的工作中,估计大多数都做过轮询调度的任务,比如定时轮询数据库同步,定时邮件通知等等。大家通过windows计划任务,windows服务等都实现过此类任务,甚至实现过自己的配置定制化的框架。那今天就来介绍个开源的调度框架quartz.net(主要介绍配置的实现,因为有朋友问过此类问题)。调度的实现代码很简单,在源码中有大量demo,这里就略过了。
quartz.net当前最新版本quartz.net 2.0 beta 1 released
一、基于文件配置
先看一下简单的实现代码
using system; using system.collections.generic; using system.linq; using system.text; using system.threading; using quartz; using quartz.impl; using common.logging; namespace demo { class program { static void main(string[] args) { // first we must get a reference to a scheduler ischedulerfactory sf = new stdschedulerfactory(); ischeduler sched = sf.getscheduler(); sched.start(); sched.shutdown(true); } } }
代码很简单,配置文件中的quartz基础配置,以及job,trigger信息是如何加载的?这个过程是发生 ischeduler sched = sf.getscheduler();过程,主要体现在源码这一段
public void initialize() { // short-circuit if already initialized if (cfg != null) { return; } if (initexception != null) { throw initexception; } namevaluecollection props = (namevaluecollection) configurationmanager.getsection("quartz"); string requestedfile = environment.getenvironmentvariable(propertiesfile); string propfilename = requestedfile != null && requestedfile.trim().length > 0 ? requestedfile : "~/quartz.config"; // check for specials propfilename = fileutil.resolvefile(propfilename); if (props == null && file.exists(propfilename)) { // file system try { propertiesparser pp = propertiesparser.readfromfileresource(propfilename); props = pp.underlyingproperties; log.info(string.format("quartz.net properties loaded from configuration file '{0}'", propfilename)); } catch (exception ex) { log.error("could not load properties for quartz from file {0}: {1}".formatinvariant(propfilename, ex.message), ex); } } if (props == null) { // read from assembly try { propertiesparser pp = propertiesparser.readfromembeddedassemblyresource("quartz.quartz.config"); props = pp.underlyingproperties; log.info("default quartz.net properties loaded from embedded resource file"); } catch (exception ex) { log.error("could not load default properties for quartz from quartz assembly: {0}".formatinvariant(ex.message), ex); } } if (props == null) { throw new schedulerconfigexception( @"could not find <quartz> configuration section from your application config or load default configuration from assembly. please add configuration to your application config file to correctly initialize quartz."); } initialize(overridewithsysprops(props)); }
通过上面代码分析,初始化首先会检查系统config中是否有<quartz> configuration section节点 (config指的app.config,web.config),如果系统config有quartz节点,则直接加载此处的配置信息。如果系统config没有quartz的基础配置信息,则会继续查找是否有quartz.config/quartz.quartz.config 这两个配置文件的存在,如果有则加载配置信息,如果没有则扔出初始化配置异常。
而jobs.xml(调度的任务和触发器plugin节点配置文件)
app.config/web.config 中plugin配置
<quartz> <add key="quartz.scheduler.instancename" value="exampledefaultquartzscheduler"/> <add key="quartz.threadpool.type" value="quartz.simpl.simplethreadpool, quartz"/> <add key="quartz.threadpool.threadcount" value="10"/> <add key="quartz.threadpool.threadpriority" value="2"/> <add key="quartz.jobstore.misfirethreshold" value="60000"/> <add key="quartz.jobstore.type" value="quartz.simpl.ramjobstore, quartz"/> <!--******************************plugin配置********************************************* --> <add key="quartz.plugin.xml.type" value="quartz.plugin.xml.xmlschedulingdataprocessorplugin, quartz" /> <add key="quartz.plugin.xml.filenames" value="quartz_jobs.xml"/> </quartz>
quartz.config 中plugin配置指向(quartz.plugin.xml.type / quartz.plugin.xml.filenames)
# you can configure your scheduler in either <quartz> configuration section # or in quartz properties file # configuration section has precedence quartz.scheduler.instancename = serverscheduler # configure thread pool info quartz.threadpool.type = quartz.simpl.simplethreadpool, quartz quartz.threadpool.threadcount = 10 quartz.threadpool.threadpriority = normal #--------------------------------*************plugin配置------------------------------------ # job initialization plugin handles our xml reading, without it defaults are used quartz.plugin.xml.type = quartz.plugin.xml.xmlschedulingdataprocessorplugin, quartz quartz.plugin.xml.filenames = ~/quartz_jobs.xml # export this server to remoting context quartz.scheduler.exporter.type = quartz.simpl.remotingschedulerexporter, quartz quartz.scheduler.exporter.port = 555 quartz.scheduler.exporter.bindname = quartzscheduler quartz.scheduler.exporter.channeltype = tcp quartz.scheduler.exporter.channelname = httpquartz
二、基于代码的方式
这种情况直接通过代码实现的,官方demo很多都是如此,我们举个例子
using system; using system.collections.generic; using system.linq; using system.text; using quartz; using quartz.impl; using system.threading; using common.logging; namespace demo { class program { static void main(string[] args) { ilog log = logmanager.getlogger(typeof(demo.hellojob)); log.info("------- initializing ----------------------"); // first we must get a reference to a scheduler ischedulerfactory sf = new stdschedulerfactory(); ischeduler sched = sf.getscheduler(); log.info("------- initialization complete -----------"); //---------------------------------------代码添加job和trigger // computer a time that is on the next round minute datetimeoffset runtime = datebuilder.evenminutedate(datetimeoffset.utcnow); log.info("------- scheduling job -------------------"); // define the job and tie it to our hellojob class ijobdetail job = jobbuilder.create<hellojob>() .withidentity("job1", "group1") .build(); // trigger the job to run on the next round minute itrigger trigger = triggerbuilder.create() .withidentity("trigger1", "group1") .startat(runtime) .build(); // tell quartz to schedule the job using our trigger sched.schedulejob(job, trigger); log.info(string.format("{0} will run at: {1}", job.key, runtime.tostring("r"))); // start up the scheduler (nothing can actually run until the // scheduler has been started) sched.start(); log.info("------- started scheduler -----------------"); // wait long enough so that the scheduler as an opportunity to // run the job! log.info("------- waiting 65 seconds... -------------"); // wait 65 seconds to show jobs thread.sleep(timespan.fromseconds(65)); // shut down the scheduler log.info("------- shutting down ---------------------"); sched.shutdown(true); log.info("------- shutdown complete -----------------"); } } }
其实代码方式已经实现了和配置文件混搭的方式了。但是这种对方式是通过配置关联加载job与trigger配置,我们还有第三种方式,自己加载job与trigger配置文件。
三、手动加载配置文件
using system; using system.collections.generic; using system.linq; using system.text; using quartz; using quartz.xml; using quartz.impl; using quartz.simpl; using system.threading; using common.logging; using system.io; namespace demo { class program { static void main(string[] args) { xmlschedulingdataprocessor processor = new xmlschedulingdataprocessor(new simpletypeloadhelper()); ischedulerfactory sf = new stdschedulerfactory(); ischeduler scheduler = sf.getscheduler(); stream s = new streamreader("~/quartz.xml").basestream; processor.processstream(s, null); processor.schedulejobs(scheduler); scheduler.start(); scheduler.shutdown(); } } }
亦或者这样
using system.text; using quartz; using quartz.xml; using quartz.impl; using quartz.simpl; using system.threading; using common.logging; using system.io; namespace demo { class program { static void main(string[] args) { xmlschedulingdataprocessor processor = new xmlschedulingdataprocessor(new simpletypeloadhelper()); ischedulerfactory sf = new stdschedulerfactory(); ischeduler scheduler = sf.getscheduler(); processor.processfileandschedulejobs("~/quartz.xml",scheduler); scheduler.start(); scheduler.shutdown(); } } }
目前根据源码分析大致就这几种配置方式,很灵活可以任意组合。 关于quartz的使用源码很详细,并且园子量有大量的学习文章。
记住quartz的配置读取方式首先app.config/web.config ---->quartz.config/quartz.quartz.config ---->quartz_jobs.xml .
通过代码方式我们可以改变quartz_jobs.xml 的指向即自己新命名的xml文件
(默认的quartz_jobs.xml是在xmlschedulingdataprocessor.quartzxmlfilename = "quartz_jobs.xml"被指定的)
方式一,通过quartz节点/quartz.config指向指定的jobs.xml。
方式二,通过xmlschedulingdataprocessor 加载指定的jobs.xml
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。
推荐阅读