zoukankan      html  css  js  c++  java
  • 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);
                }
            }
        }
    }
    View Code

    三:插件配置

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

    有三种配置方式:

    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必须设置为始终复制=>右键属性,复制到输出目录选项选择始终复制

  • 相关阅读:
    linux环境weblogic开启远程调试
    C#相关资料
    pyqt5,pyside2学习过程中问题与疑惑记录--先记下问题,然后逐个解决
    任务记录-2020.10.1
    猜想:假如时间的快慢与物体的质量有关系。那长大之后,感觉时间过得越来越快,是不是大脑或者身体中某一个器官越长越大,然后导致时间越过越快。。。
    学习思路--学习一个新的东西,从哪些方面着手
    java bug记录
    记录要做的事情,把sql字符串替换写成工具网页。
    使用java代码本地测试远程rpc接口
    任务记录
  • 原文地址:https://www.cnblogs.com/Francis-YZR/p/5424651.html
Copyright © 2011-2022 走看看