Quartz.Net AnnualCalendar And PlugInConfigure

正如标题所示,文章主要是围绕Quartz.Net作业调度框架话题展开的,内容出自博主学习官方Examples的学习心得与体会,文中难免会有错误之处,还请指出得以指教。

一: Calendar

前面演示过根据秒-分-时 日-月-星期等触发时机来定义一个轮询的作业调度,在实际生活中,除此之外还有根据日历来调度作业,根据日历定义触发轮询周期也是比较常用常见的功能。

在Quartz.Net中日历是由AnnualCalendar类定义的,实例化一个AnnualCalendar对象,往这个对象添加自定义的日期构成自定义的一个日历触发时机集合。

举个例子:

           //日历对象
            AnnualCalendar holidays = new AnnualCalendar();

            // 元旦
            DateTime NewYearDay = new DateTime(DateTime.UtcNow.Year, 1, 1);
            holidays.SetDayExcluded(NewYearDay , true);

            // 国庆节
            DateTime NationalDay= new DateTime(DateTime.UtcNow.Year, 10, 1);
            holidays.SetDayExcluded(NationalDay, true);

            // 光棍节
            DateTime SinglesDay= new DateTime(DateTime.UtcNow.Year, 11, 11);
            holidays.SetDayExcluded(SinglesDay, true);

有了日历对象之后,需要将日历对象附加到调度实例上,并且在触发器中使用ModifiedByCalendar("日历对象")来指定按照日历对象进行调度。

下面贴出根据日历对象指定的日期进行作业调度的代码(仅供参考):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Quartz.Impl.Calendar;
using Quartz.Impl;
using Common.Logging;

namespace Quartz.Examples
{
    /// <summary>
    /// This example will demonstrate how calendars can be used
    /// to exclude periods of time when scheduling should not
    /// take place.
    /// 一个根据日历(节假日)来设定调度作业的演示
    /// </summary>
    /// <author>Marko Lahma (.NET)</author>
    public class CalendarExample : IExample
    {
        public string Name
        {
            get { return GetType().Name; }
        }

        public virtual void Run()
        {
            ILog log = LogManager.GetLogger(typeof(CalendarExample));

            log.Info("------- Initializing ----------------------");

            // First we must get a reference to a scheduler
            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            log.Info("------- Initialization Complete -----------");

            log.Info("------- Scheduling Jobs -------------------");

            // Add the holiday calendar to the schedule   //就是自定义节假日   比如我们可以事先根据日历设定7月4号,10月31号,12月25号作为调度时机
            AnnualCalendar holidays = new AnnualCalendar();

            // fourth of July (July 4)
            DateTime fourthOfJuly = new DateTime(DateTime.UtcNow.Year, 7, 4);
            holidays.SetDayExcluded(fourthOfJuly, true);

            // halloween (Oct 31)
            DateTime halloween = new DateTime(DateTime.UtcNow.Year, 10, 31);//10月31号
            holidays.SetDayExcluded(halloween, true);

            // christmas (Dec 25)
            DateTime christmas = new DateTime(DateTime.UtcNow.Year, 12, 25);
            holidays.SetDayExcluded(christmas, true);

            // tell the schedule about our holiday calendar
            sched.AddCalendar("holidays", holidays, false, false);

            //设定开启调度日历的时间
            DateTimeOffset runDate = DateBuilder.DateOf(10, 0, 0, 31, 10);//10.31早上10点开启调度作业

            IJobDetail job = JobBuilder.Create<SimpleJob>()
                .WithIdentity("job1", "group1")
                .Build();

            ISimpleTrigger trigger = (ISimpleTrigger)TriggerBuilder.Create()
                                                          .WithIdentity("trigger1", "group1")
                                                          .StartAt(runDate)
                                                          .WithSimpleSchedule(x => x.WithIntervalInHours(1).RepeatForever())
                                                          .ModifiedByCalendar("holidays")
                                                          .Build();

            // schedule the job and print the first run date
            DateTimeOffset firstRunTime = sched.ScheduleJob(job, trigger);

            log.Info(string.Format("{0} will run at: {1} and repeat: {2} times, every {3} seconds", job.Key, firstRunTime.ToString("r"), trigger.RepeatCount, trigger.RepeatInterval.TotalSeconds));

            log.Info("------- Starting Scheduler ----------------");
            sched.Start();
            log.Info("------- Waiting 30 seconds... --------------");
            try
            {
                // wait 30 seconds to show jobs
                Thread.Sleep(30 * 1000);
                // executing...
            }
            catch (ThreadInterruptedException)
            {
            }

            // shut down the scheduler
            log.Info("------- Shutting Down ---------------------");
            sched.Shutdown(true);
            log.Info("------- Shutdown Complete -----------------");

            SchedulerMetaData metaData = sched.GetMetaData();
            log.Info(string.Format("Executed {0} jobs.", metaData.NumberOfJobsExecuted));
        }
    }
}

AnnualCalendar

二:监听对象

在Quartz.Net框架中提供了一个监听器IJobListener接口,实现该接口实例化一个子类,这个子类可以监听一个作业id来触发本身的void JobWasExecuted(IJobExecutionContext inContext, JobExecutionException inException)方法:这个方法里面带了IJobExecutionContext inContext参数,inContext.Scheduler其实就是程序的调度实例,我们知道通过调度实例可以添加作业以及触发器(定制一个轮询的调度任务)并且Start()开启执行任务。

这样看来,通过实现IJobListener接口得到监听器类中的JobWasExecuted()方法里可以再次定义轮询调度作业。

比如当需要满足以下需求时可以使用监听器来实现:

=>在A任务顺利开启执行后,轮询调度B任务。(此时B任务就定义在监听器类里面)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Quartz.Impl.Matchers;
using Quartz.Impl;
using Common.Logging;

namespace Quartz.Examples
{

    public class ListenerExample : IExample
    {
        public string Name
        {
            get { return GetType().Name; }
        }

        public virtual void Run()
        {
            ILog log = LogManager.GetLogger(typeof(ListenerExample));

            log.Info("------- Initializing ----------------------");

            // First we must get a reference to a scheduler
            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            log.Info("------- Initialization Complete -----------");

            log.Info("------- Scheduling Jobs -------------------");

            // schedule a job to run immediately
            IJobDetail job = JobBuilder.Create<SimpleJob1>()
                .WithIdentity("job1")
                .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("trigger1")
                .StartNow()
                .Build();
            //IJobListener监听器接口,实现该接口得到自定义的Job1Listener类,在该类中实现JobWasExecuted()方法,在方法中可以添加作业触发器

            //监听类的意义更在于在一个作业成功运行之后,触发绑定的另外一些操作,这些操作在监听类中定义并调度。
            // Set up the listener
            //设定监听程序,实例话Job1Listener()监听类
            IJobListener listener = new Job1Listener();
            IMatcher<JobKey> matcher = KeyMatcher<JobKey>.KeyEquals(job.Key);
            sched.ListenerManager.AddJobListener(listener, matcher);//根据作业key为响应作业添加监听

            sched.ScheduleJob(job, trigger);
            log.Info("------- Starting Scheduler ----------------");
            sched.Start();
            log.Info("------- Waiting 30 seconds... --------------");
            try
            {
                // wait 30 seconds to show jobs
                Thread.Sleep(TimeSpan.FromSeconds(30));
                // executing...
            }
            catch (ThreadInterruptedException)
            {
            }

            // shut down the scheduler
            log.Info("------- Shutting Down ---------------------");
            sched.Shutdown(true);
            log.Info("------- Shutdown Complete -----------------");

            SchedulerMetaData metaData = sched.GetMetaData();
            log.Info(string.Format("Executed {0} jobs.", metaData.NumberOfJobsExecuted));
        }
    }
}

ListenerExample

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Common.Logging;

namespace Quartz.Examples
{
    ///监听程序可以附加到作业中,附加了监听器的作业在进行调度的时候,准备执行,否决,执行完毕三个状态
    ///并且在监听程序可以实例化IJobDetail类创建新作业
    public class Job1Listener : IJobListener
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(Job1Listener));

        public virtual string Name
        {
            get { return "job1_to_job2"; }
        }

        public virtual void JobToBeExecuted(IJobExecutionContext inContext)
        {
            log.Info("Job1Listener says: Job Is about to be 执行.");//执行
        }

        public virtual void JobExecutionVetoed(IJobExecutionContext inContext)
        {
            log.Info("Job1Listener says: Job Execution was 否决.");//否决
        }

        public virtual void JobWasExecuted(IJobExecutionContext inContext, JobExecutionException inException)
        {
            log.Info("Job1Listener says: Job was 执行 完毕.");

            // Simple job #2
            //监听程序调度作业
            IJobDetail job2 = JobBuilder.Create<SimpleJob2>()
                .WithIdentity("job2")
                .Build();

            ITrigger trigger = TriggerBuilder.Create()
                .WithIdentity("job2Trigger")
                .StartNow()
                .Build();

            try
            {
                // schedule the job to run!
                inContext.Scheduler.ScheduleJob(job2, trigger);
            }
            catch (SchedulerException e)
            {
                log.Warn("Unable to schedule job2!");
                Console.Error.WriteLine(e.StackTrace);
            }
        }
    }
}

三:插件配置

官方给出的名字叫做插件,其实我认为,这只是一种关于如何调度作业的配置。

有三种配置方式:

1.通过代码实例化NameValueCollection对象,往NameValueCollection对象以键值对形式赋值,然后在调度工厂对象中传入该NameValueCollection对象得到调度实例。

            var properties = new NameValueCollection();
            properties["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin";

            properties["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin";//插件
            properties["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml";//读取这个配置文件
            properties["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true";
            properties["quartz.plugin.jobInitializer.scanInterval"] = "120";//120秒一次

            // First we must get a reference to a scheduler
            ISchedulerFactory sf = new StdSchedulerFactory(properties);
            IScheduler sched = sf.GetScheduler();            sched.Start();

通过这样方式无须再使用代码定义作业对象IJobDetail以及触发器ITrigger等,而是通过properties["quartz.plugin.jobInitializer.fileNames"]指定的xml文件来设置:

<?xml version="1.0" encoding="UTF-8"?>

<job-scheduling-data xmlns="http://quartznet.sourceforge.net/JobSchedulingData"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 version="2.0">

  <processing-directives>
    <overwrite-existing-data>true</overwrite-existing-data>
  </processing-directives>

  <schedule>

    <job>
      <name>jobName1</name>
      <group>jobGroup1</group>
      <description>jobDesciption1</description>
      <job-type>Quartz.Examples.SimpleJob3, Quartz.Examples</job-type>
      <durable>true</durable>
      <recover>false</recover>
      <job-data-map>
        <entry>
          <key>key0</key>
          <value>value0</value>
        </entry>
        <entry>
          <key>key1</key>
          <value>value1</value>
        </entry>
        <entry>
          <key>key2</key>
          <value>value2</value>
        </entry>
      </job-data-map>
    </job>

    <trigger>
      <simple>
        <name>simpleName</name>
        <group>simpleGroup</group>
        <description>SimpleTriggerDescription</description>
        <job-name>jobName1</job-name>
        <job-group>jobGroup1</job-group>
        <start-time>1982-06-28T18:15:00.0Z</start-time>
        <end-time>2020-05-04T18:13:51.0Z</end-time>
        <misfire-instruction>SmartPolicy</misfire-instruction>
        <repeat-count>100</repeat-count>
        <repeat-interval>3000</repeat-interval>
      </simple>
    </trigger>

  </schedule>

</job-scheduling-data>

quartz_jobs.xml

注意点:

1.1 quartz_jobs.xml必须设置为始终复制=>右键属性,复制到输出目录选项选择始终复制

1.2 要将NameValueCollection对象传入StdSchedulerFactory工厂中以得到调试实例对象

ISchedulerFactory sf = new StdSchedulerFactory(properties);

2.通过app.config或者web.config配置文件

通过这种方式定义调度作业的信息将会放置在app.config或web.config配置文件中,在代码中只需要得到一个无参的StdSchedulerFactory()实例对象,开启调度即可:

            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            // start the schedule
            sched.Start();

app.config配置文件内容:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <configSections>
        <section name="quartz" type="System.Configuration.NameValueSectionHandler, System, Version=1.0.5000.0,Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
        <sectionGroup name="common">
            <section name="logging" type="Common.Logging.ConfigurationSectionHandler, Common.Logging" />
        </sectionGroup>
    </configSections>

    <common>
        <logging>
            <factoryAdapter type="Common.Logging.Log4Net.Log4NetLoggerFactoryAdapter, Common.Logging.Log4net1213">
                <arg key="configType" value="INLINE" />
            </factoryAdapter>
        </logging>
    </common>

    <log4net>
        <appender name="ConsoleAppender" type="log4net.Appender.ConsoleAppender">
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%d [%t] %-5p %l - %m%n" />
            </layout>
        </appender>
        <appender name="EventLogAppender" type="log4net.Appender.EventLogAppender">
            <layout type="log4net.Layout.PatternLayout">
                <conversionPattern value="%d [%t] %-5p %l - %m%n" />
            </layout>
        </appender>
        <root>
            <level value="INFO" />
            <appender-ref ref="ConsoleAppender" />
      <!-- uncomment to enable event log appending -->
            <!-- <appender-ref ref="EventLogAppender" /> -->
        </root>
    </log4net>

  <!--
    We use quartz.config for this server, you can always use configuration section if you want to.
    Configuration section has precedence here.
  -->

  <quartz>
    <add key="quartz.plugin.triggHistory.type" value="Quartz.Plugin.History.LoggingJobHistoryPlugin"/>
    <add key="quartz.plugin.jobInitializer.type" value="Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin"/>
    <add key="quartz.plugin.jobInitializer.fileNames" value="quartz_jobs.xml"/>
    <add key="quartz.plugin.jobInitializer.failOnFileNotFound" value="true"/>
    <add key="quartz.plugin.jobInitializer.scanInterval" value="120"/>
  </quartz>

  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="Common.Logging" publicKeyToken="af08829b84f0328e" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
      <dependentAssembly>
        <assemblyIdentity name="log4net" publicKeyToken="669e0ddf0bb1aa2a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-1.2.13.0" newVersion="1.2.13.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

App.config

在app.config中会指定调度任务信息的一个路径,比如quartz_jobs.xml文件,通过读取这个xml文件来获取调度任务。

2.1 quartz_jobs.xml必须设置为始终复制=>右键属性,复制到输出目录选项选择始终复制

3.通过quartz.config配置文件

# 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

quartz.config

在代码中只需要得到一个无参的StdSchedulerFactory()实例对象,开启调度即可:

            ISchedulerFactory sf = new StdSchedulerFactory();
            IScheduler sched = sf.GetScheduler();

            // start the schedule
            sched.Start();

3.1 quartz_jobs.xml必须设置为始终复制=>右键属性,复制到输出目录选项选择始终复制

3.2 quartz.config必须设置为始终复制=>右键属性,复制到输出目录选项选择始终复制

时间: 2024-11-07 12:15:09

Quartz.Net AnnualCalendar And PlugInConfigure的相关文章

Quartz.Net目录

The first talk about what is Quartz.Net About Quartz.Net Build the environment and some example Quartz.Net Cron Expression Quartz.Net State Maintenance And Exception Handling Quartz.Net AnnualCalendar And PlugInConfigure Quartz.Net Cluster-DatabaseSu

Quartz 入门详解

Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,它可以与J2EE与J2SE应用程序相结合也可以单独使用.Quartz可以用来创建简单或为运行十个,百个,甚至是好几万个Jobs这样复杂的日程序表.Jobs可以做成标准的Java组件或 EJBs.官方网站:http://www.opensymphony.com/quartz 相关Jar:   quartz-all-1.6.0.jar   jta.jar   commons-logging-1.1.jar

Quartz使用总结

废话的前言 以前凭借年轻,凡事都靠脑记.现在工作几年后发现,很多以前看过.用过的东西,再次拿起的时候总觉得记不牢靠."好记性不如烂笔头"应该是某位上了年纪的大叔的切肤之痛(仅次于上了年纪的难言之瘾). 我觉得这事得怪怪中国的应试教育,中国的考试方式就是要求把脑袋当数据库,以前中学那点知识,确实还能装得下.但现在所需的知识量再一次性装入大脑,就是内存溢出的节奏.另,再相信什么人脑只开发5%的蠢话了(「人脑只用了不到 5%」 的说法是否确有科学依据?).更可行的方式,应该学学数据库,大脑只

(5)Quartz学习

原文:http://blog.csdn.net/zxl315/article/details/10879927 介绍Quartz Quartz是一个开源的任务调度系统,它能用来调度很多任务的执行. 运行环境 Quartz 能嵌入在其他应用程序里运行. Quartz 能在一个应用服务器里被实例化(或servlet容器), 并且参与XA事务 Quartz能独立运行(通过JVM),或者通过RMI Quartz能被集群实例化 任务调度 当一个指定给任务的触发器发生时,任务就被调度执行. 触发器能被创建为

Quartz定时器入门总结

链接地址:http://www.cnblogs.com/drift-ice/p/3817269.html 废话的前言 以前凭借年轻,凡事都靠脑记.现在工作几年后发现,很多以前看过.用过的东西,再次拿起的时候总觉得记不牢靠."好记性不如烂笔头"应该是某位上了年纪的大叔的切肤之痛(仅次于上了年纪的难言之瘾). 我觉得这事得怪怪中国的应试教育,中国的考试方式就是要求把脑袋当数据库,以前中学那点知识,确实还能装得下.但现在所需的知识量再一次性装入大脑,就是内存溢出的节奏.另,再相信什么人脑只开

Quartz任务调度快速入门

Quartz任务调度快速入门 概述 了解Quartz体系结构 Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器.任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述: ●Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息.Job运行时的信息保存在JobDataMap实例中: ●Jo

【Quartz】Quartz概述及入门实例

林炳文Evankaka原创作品.转载请注明出处http://blog.csdn.net/evankaka Quartz 在开源任务调度框架中的翘首,它提供了强大任务调度机制,难能可贵的是它同时保持了使用的简单性.Quartz 允许开发人员灵活地定义触发器的调度时间表,并可以对触发器和任务进行关联映射.        此外,Quartz提供了调度运行环境的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失.此外,Quartz还提供了组件式的侦听器.各种插件.线程池等

Quartz任务调度快速入门(转)

概述 了解Quartz体系结构 Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器.任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述: ●Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息.Job运行时的信息保存在 JobDataMap实例中: ●JobDetail:Quartz

Quartz任务调度快速入门(转)

转自http://www.blogjava.net/baoyaer/articles/155645.html 概述 了解Quartz体系结构 Quartz对任务调度的领域问题进行了高度的抽象,提出了调度器.任务和触发器这3个核心的概念,并在org.quartz通过接口和类对重要的这些核心概念进行描述: ●Job:是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调