业调度框架_Quartz

什么是Quartz


Quartz是一个完全由Java编写的开源作业调度框架,为在Java应用程序中进行作业调度提供了简单却强大的机制。Quartz允许开发人员根据时间间隔来调度作业。它实现了作业和触发器的多对多的关系,还能把多个作业与不同的触发器关联。简单地创建一个org.quarz.Job接口的Java类,Job接口包含唯一的方法:

    public void execute(JobExecutionContext context) throws JobExecutionException;

在Job接口实现类里面,添加需要的逻辑到execute()方法中。配置好Job实现类并设定好调度时间表,Quartz就会自动在设定的时间调度作业执行execute()。

整合了Quartz的应用程序可以重用不同事件的作业,还可以为一个事件组合多个作业。Quartz通过属性文件来配置JDBC事务的数据源、全局作业、触发器侦听器、插件、线程池等等。

Quartz是由James House创建并最初于2001年春天被加入sourceforge工程。接下来的几年里,有很多的新特性和版本出现,但是直到项目迁移到新的站点并成为OpenSymphony项目家族的一员,才开始真正启动并受到也有的关注。

目前的版本已经是2.0以上,v2.x相对于v1.x有很多新特性出现,并有很多的改动,具体参见Quartz官网上说明。这里介绍的仍然是v1.x(v1.8.6)。

 "Hello, Quartz"


配置环境:

1. 下载Quartz

2. 阅读Readme.txt,了解每个jar包的作用,将quartz.jar包和lib/下的几个jar包、以及相关依赖的jar包放在工程的classpath中

先来看一个简单的Quartz应用,让它每隔5s打印"Hello, Quartz",打印10次。

代码清单1:创建任务

import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public class HelloQuartzJob implements Job {

public void execute(JobExecutionContext context) 
            throws JobExecutionException {
        System.out.println("Hello, Quartz! - executing its JOB at "+ 
            new Date() + " by " + context.getTrigger().getName());
    }
}

为了调度此任务执行,需要先得到一个Schedule实例,然后创建一个包含任务信息的JobDetail,最后创建一个Trigger管理任务的执行。

代码清单2:调度任务

import java.sql.Date; 
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleTrigger;
import org.quartz.impl.StdSchedulerFactory;

public class HelloQuartzScheduling {

public static void main(String[] args)throws SchedulerException {

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

JobDetail jobDetail = new JobDetail("helloQuartzJob", 
                Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

SimpleTrigger simpleTrigger = new SimpleTrigger("simpleTrigger", 
                Scheduler.DEFAULT_GROUP);

simpleTrigger.setStartTime(new Date(System.currentTimeMillis()));
        simpleTrigger.setRepeatInterval(5000);
        simpleTrigger.setRepeatCount(10);

scheduler.scheduleJob(jobDetail, simpleTrigger);

scheduler.start();
    }

}

运行结果:

可以看到,其实它执行了11次。此处没有配置log4j.properties属性文件。

整个任务创建及调度的简单示意图如下。

Job接口包含唯一方法execute(),将任务逻辑添加到该方法中。StdSchedulerFactory.getScheduler()返回一个可运行的实例,然后创建调度任务的JobDetail实例,并传递3个参数给构造方法。第一个参数是任务名,用于引用该任务。第二个参数是任务组名,这里使用默认名,任务组名用于引用集合起来的一组任务,如可以使用Scheduler.pauseJobGroup()来暂停一组任务,每个组中的任务名是唯一的。第三个参数是实现特定任务的类。创建JobDetail实例后,需要创建一个Trigger,这里使用的是SimpleTrigger类,它提供了JDK Timer风格的触发器行为。传递给SimpleTrigger构造方法的两个参数分别是触发器名和任务组名,触发器名在它所在的任务组中必须是唯一的。接下来是设置触发器的一些属性,setStartTime()是设置启动时间,setRepeatInterval()是设置重复间隔,setRepeatCount()是设置重复次数。最后,scheduler.start()启动调度,终止调度可以用stop()方法。

 CronTrigger类


Quartz有两大触发器,除了上面使用的SimpleTrigger外,就是CronTrigger。CronTrigger能够提供复杂的触发器表达式的支持。CronTrigger是基于Unix Cron守护进程,它是一个调度程序,支持简单而强大的触发器语法。

使用CronTrigger主要的是要掌握Cron表达式。Cron表达式包含6个必要组件和一个可选组件,如下表所示。


位置


含义


允许的特殊字符


1


秒(0~59)


, -  *  /


2


分(0~59)


, -  *  /


3


小时(0~24)


, -  *  /


4


日期(1~31)


, -  *  /  ?  L  W  C


5


月(JAN~DEC或1~12)


, -  *  /


6


星期(SUN~SAT或1~7)


, -  *  /  ?  L  C  #


7


年(可选,1970~2099),若为空,表示全部时间范围


, -  *  /

特殊字符的含义,见下表。


特殊字符


说明


*


通配符,任意值


?


无特定值。通常和其他指定的值一起使用,表示必须显示该值但不能检查


-


范围。e.g.小时部分10-12表示10:00,11:00, 12:00


,


列分隔符。可以让你指定一系列的值。e.g.在星期域中指定MON、TUE和WED


/


增量。表示一个值的增量,e.g.分钟域中0/1表示从0开始,每次增加1min


L


表示Last。它在日期和星期域中表示有所不同。在日期域中,表示这个月的最后一天,而在星期域中,它永远是7(星期六)。当你希望使用星期中某一天时,L字符非常有用。e.g.星期域中6L表示每一个月的最后一个星期五


W


在本月内离当天最近的工作日触发,所谓的最近工作日,即当天到工作日的前后最短距离,如果当天即为工作日,则距离是0;所谓本月内指的是不能跨月取到最近工作日,即使前/后月份的最后一天/第一天确实满足最近工作日。e.g. LW表示本月的最后一个工作日触发,W强烈依赖月份。


#


表示该月的第几个星期,e.g. 1#2表示每一个月的第一个星期一


C


日历值。日期值是根据一个给定的日历计算出来的。在日期域中给定一个20C将在20日(日历包括20日)或20日后日历中包含的第一天(不包括20日)激活触发器。例如在一个星期域中使用6C表示日历中星期五(日历包括星期五)或者第一天(日历不包括星期五)

Cron表达式举例:

"30 * * * * ?" 每半分钟触发任务

"30 10 * * * ?" 每小时的10分30秒触发任务

"30 10 1 * * ?" 每天1点10分30秒触发任务

"30 10 1 20 * ?" 每月20号1点10分30秒触发任务

"30 10 1 20 10 ? *" 每年10月20号1点10分30秒触发任务

"30 10 1 20 10 ? 2011" 2011年10月20号1点10分30秒触发任务

"30 10 1 ? 10 * 2011" 2011年10月每天1点10分30秒触发任务

"30 10 1 ? 10 SUN 2011" 2011年10月每周日1点10分30秒触发任务

"15,30,45 * * * * ?" 每15秒,30秒,45秒时触发任务

"15-45 * * * * ?" 15到45秒内,每秒都触发任务

"15/5 * * * * ?" 每分钟的每15秒开始触发,每隔5秒触发一次

"15-30/5 * * * * ?" 每分钟的15秒到30秒之间开始触发,每隔5秒触发一次

"0 0/3 * * * ?" 每小时的第0分0秒开始,每三分钟触发一次

"0 15 10 ? * MON-FRI" 星期一到星期五的10点15分0秒触发任务

"0 15 10 L * ?" 每个月最后一天的10点15分0秒触发任务

"0 15 10 LW * ?" 每个月最后一个工作日的10点15分0秒触发任务

"0 15 10 ? * 5L" 每个月最后一个星期四的10点15分0秒触发任务

"0 15 10 ? * 5#3" 每个月第三周的星期四的10点15分0秒触发任务

将上面HelloQuartz例子中SimpleTrigger换成CronTrigger,代码如下。

代码清单3:CronTrigger调度器

import java.text.ParseException;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;

public class HelloQuartzScheduling {

public static void main(String[] args) 
        throws SchedulerException, ParseException {

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

JobDetail jobDetail = new JobDetail("helloQuartzJob", 
                Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

String cronExpression = "30/5 * * * * ?"; // 每分钟的30s起,每5s触发任务        
        CronTrigger cronTrigger = new CronTrigger("cronTrigger", 
                Scheduler.DEFAULT_GROUP, cronExpression);

scheduler.scheduleJob(jobDetail, cronTrigger);

scheduler.start();
    }

}

运行结果:

CronTrigger使用HolidayCalendar类可以排除某一段时间,比如说国庆节不执行调度任务,代码示例如下:

代码清单4:HolidayCalendar的使用

import java.text.ParseException;
import java.util.Calendar;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.calendar.HolidayCalendar;

public class HelloQuartzScheduling {

public static void main(String[] args) 
        throws SchedulerException, ParseException {

SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();

JobDetail jobDetail = new JobDetail("helloQuartzJob", 
                Scheduler.DEFAULT_GROUP, HelloQuartzJob.class);

Calendar cal = Calendar.getInstance();
        cal.set(2012, Calendar.OCTOBER, 1); // 国庆节

HolidayCalendar holidayCal = new HolidayCalendar();
        holidayCal.addExcludedDate(cal.getTime()); // 排除该日期

// addCalendar(String calName, Calendar calendar, 
        //             boolean replace, boolean updateTriggers)
        scheduler.addCalendar("calendar", holidayCal, true, false);

String cronExpression = "30/5 * * * * ?"; // 每5s触发任务        
        CronTrigger cronTrigger = new CronTrigger("cronTrigger", 
                Scheduler.DEFAULT_GROUP, cronExpression);

cronTrigger.setCalendarName("calendar");

scheduler.scheduleJob(jobDetail, cronTrigger);

scheduler.start();
    }

}

 JobStore: 任务持久化


Quartz支持任务持久化,这可以让你在运行时增加任务或者对现存的任务进行修改,并为后续任务的执行持久化这些变更和增加的部分。中心概念是JobStore接口。默认的是RAMJobStore。

 配置文件


上述没有用到任何的配置文件。Quartz支持配置文件,它的好处是比编写代码简单,且修改后不需要重新编译源码。

>> 配置quartz.properties特性文件

quartz.properties文件定义了Quartz应用运行时行为,还包含了许多能控制Quartz运转的属性。它应放在工程的classpath中。

代码清单5:quartz.properties

#============================================================================  
# Configure Main Scheduler Properties  
#============================================================================

# 实例名
org.quartz.scheduler.instanceName = QuartzScheduler 
# 实例ID
org.quartz.scheduler.instanceId = AUTO

#============================================================================
# Configure ThreadPool  
#============================================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 线程个数
org.quartz.threadPool.threadCount = 3
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore  
#============================================================================
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

#============================================================================
# Configure Plugins 
#============================================================================
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin
# org.quartz.plugins.xml.JobInitializationPlugin是Quartz自带的插件,
# 默认时,这个插件会在 classpath 中搜索名为 quartz_jobs.xml 
# 的文件并从中加载 Job 和 Trigger 信息
# v1.8之前用JobInitializationPlugin
#org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin
org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin
org.quartz.plugin.jobInitializer.fileNames = quartz_jobs.xml
org.quartz.plugin.jobInitializer.failOnFileNotFound = true
org.quartz.plugin.jobInitializer.scanInterval =10
org.quartz.plugin.jobInitializer.wrapInUserTransaction = false

# 关闭quartz新版本检测功能
org.quartz.scheduler.skipUpdateCheck = true

>> 配置quartz_jobs.xml文件

在配置quart_jobs.xml时,遇到一个问题:

Exception in thread "main" org.quartz.SchedulerException: SchedulerPlugin class‘org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin;‘ couldnot be instantiated.

因为quartz从版本1.8开始,配置文件有所改动,以前quartz自带的插件是JobInitializationPlugin,而1.8中是XMLSchedulingDataProcessorPlugin. xml schema亦有所改变,难道是改变后配置不对?错误提示是插件类找不到,jar包也都加入到工程了啊。最后终于发现,在quartz.properties特性文件中配置插件行最后多打了个分号。原来是一个多余的分号引发的错误!

下面是新的xml配置文件格式示例。

代码清单6:quartz_jobs.xml格式 

<?xmlversion="1.0"encoding="UTF-8"?>

<job-scheduling-dataxmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.ogr/xml/job_scheduling_data_1_8.xsd"

version="1.8">

<pre-processing-commands>

<!--在执行作业和触犯器之前执行的命令-->

<delete-jobs-in-group>*</delete-jobs-in-group>

<!--删除标示组中的所有作业,如果是“*”,则删除所有组中的作业,同时也会删除与作业有关的触犯器 -->

<delete-triggers-in-group>*</delete-triggers-in-group>

<!--删除标示组中的所有触犯器,如果是“*”,则删除所有组中的触发器 -->

<delete-job>

<!--删除指定的作业,同时也会删除与它关联的触犯器 -->

<name></name>

<group></group>

</delete-job>

<delete-trigger>

<!--删除指定的触犯器 -->

<name></name>

<group></group>

</delete-trigger>

</pre-processing-commands>

<processing-directives>

<!--在计划作业和触发器是应遵循的命令和原则 -->

<overwrite-existing-data>true or false</overwrite-existing-data>

<!--是否复写已经存在的任务计划数据,如果为false并且ingore-duplicates非false,那么文件中同名的触发器或作业将会继续存在,则会产生错误-->

<ignore-duplicates>true or false</ignore-duplicates>

<!--如果为true,计划中的任何同名的作业/触发器将会被忽略,不会产生错误-->

</processing-directives>

<schedule>

<job>

<name>JobName</name>

<group>JobGroup</group>

<description></description>

<job-class></job-class>

<job-listener-ref></job-listener-ref>

<!-- volatility,durability,recover必须按顺序设定 -->

<volatility></volatility>

<durability></durability>

<recover></recover>

<job-data-map>

<!-- entry可以设定多个-->

<entry>

<key></key>

<value></value>

</entry>

</job-data-map>

</job>

<trigger>

<!-- Trigger分为simple,cron,date-interval三种类型,一个trigger中只能指定一种类型-->

<simple>

<name></name>

<group></group>

<description></description>

<job-name></job-name>

<job-group></job-group>

<calendar-name></calendar-name>

<volatility></volatility>

<job-data-map>

<entry>

<key></key>

<value></value>

</entry>

</job-data-map>

<start-time></start-time>

<end-time></end-time>

<misfire-instruction></misfire-instruction>

<repeat-count></repeat-count>

<repeat-interval></repeat-interval>

</simple>

<cron>

<name></name>

<group></group>

<description></description>

<job-name></job-name>

<job-group></job-group>

<calendar-name></calendar-name>

<volatility></volatility>

<job-data-map>

<entry>

<key></key>

<value></value>

</entry>

</job-data-map>

<start-time></start-time>

<end-time></end-time>

<misfire-instruction></misfire-instruction>

<cron-expression></cron-expression>

<time-zone></time-zone>

</cron>

<date-interval>

<name></name>

<group></group>

<description></description>

<job-name></job-name>

<job-group></job-group>

<calendar-name></calendar-name>

<volatility></volatility>

<job-data-map>

<entry>

<key></key>

<value></value>

</entry>

</job-data-map>

<start-time></start-time>

<end-time></end-time>

<misfire-instruction></misfire-instruction>

<repeat-interval></repeat-interval>

<repeat-interval-unit></repeat-interval-unit>

</date-interval>

</trigger>

</schedule>

</job-scheduling-data>

代码清单7:quartz_jobs.xml示例

<?xmlversion="1.0"encoding="UTF-8"?>

<job-scheduling-dataxmlns="http://www.quartz-scheduler.org/xml/JobSchedulingData"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.quartz-scheduler.org/xml/JobSchedulingData http://www.quartz-scheduler.org/xml/job_scheduling_data_1_8.xsd"

version="1.8">

<pre-processing-commands>

<delete-jobs-in-group>*</delete-jobs-in-group> <!-- clear all jobs in scheduler -->

<delete-triggers-in-group>*</delete-triggers-in-group><!-- clear all triggers in scheduler -->

</pre-processing-commands>

<processing-directives>

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

<ignore-duplicates>false</ignore-duplicates>

</processing-directives>

<schedule>

<job>

<name>helloQuartzJob</name>

<group>DEFAULT</group>

<description>简单的quartz使用</description>

<job-class>HelloQuartzJob</job-class>

<volatility>false</volatility>

<durability>true</durability>

<recover>false</recover>

</job>

<trigger>

<cron>

<name>trigger</name>

<group>DEFAULT</group>

<job-name>helloQuartzJob</job-name>

<job-group>DEFAULT</job-group>

<cron-expression>30/5 * * * * ?</cron-expression>

</cron>

</trigger>

</schedule>

</job-scheduling-data>

代码清单8:Quartz任务调度

public class HelloQuartzScheduling {
    
    public static void main(String[] args) 
       throws SchedulerException, ParseException {
       
       SchedulerFactory schedulerFactory = new StdSchedulerFactory();
       Scheduler scheduler = schedulerFactory.getScheduler();
       
       scheduler.start();              
    }   
}

这里遇到个问题,提示错误:

Exception in thread "main" Java.lang.NoClassDefFoundError: javax/transaction/UserTransaction

是由于缺少jta.jar,google出的结果是在quartz发行包的/lib中有此jar包,但是在1.8中没有找到。下载quartz 1.7中,也没有找到,因此,在网上搜一个jta.jar包放置过程classpath中,然后编译运行,ok.

时间: 2024-11-08 18:52:12

业调度框架_Quartz的相关文章

详解应对平台高并发的分布式调度框架TBSchedule

tbschedule是一款非常优秀的高性能分布式调度框架,非常高兴能分享给大家.这篇文章是我结合多年tbschedule使用经验和研读三遍源码的基础上完成的,期间和阿里空玄有过不少技术交流,非常感谢空玄给予的大力支持.我写这篇文章的目的一是出于对tbschedule的一种热爱,二是现在是一个资源共享.技术共享的时代,希望把它展现给大家(送人玫瑰,手留余香),能给大家的工作带来帮助. 一.tbschedule初识 时下互联网和电商领域,各个平台都存在大数据.高并发的特点,对数据处理的要求越来越高,

java并行调度框架封装及示例

参考资料:  阿里巴巴开源项目 CobarClient  源码实现. 分享作者:闫建忠 分享时间:2014年5月7日 --------------------------------------------------------------------------------------- 并行调度封装类设计: BXexample.java package org.hdht.business.ordermanager.quartzjob; import java.util.ArrayList;

山寨版Quartz.Net任务统一调度框架

TaskScheduler 在日常工作中,大家都会经常遇到Win服务,在我工作的这些年中一直在使用Quartz.Net这个任务统一调度框架,也非常好用,配置简单,但是如果多个项目组的多个服务部署到一台服务器时还是不尽如人意. 这段时间很忙,也一直未更新博客了,赶上今天下班早,就研究了一下,弄了个简单版基于Timer的山寨Quartz,当然了只是实现任务调度,闲话少说直接入主题吧 一.技术准备 其实都是普通的微软技术,一想到这方我们第一想到的可能就是反射,本文用了MEF 二.框架搭建 第一我们建立

Quartz.net 开源job调度框架

Quartz.NET是一个开源的作业调度框架,非常适合在平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等. Quartz.NET允许开发人员根据时间间隔(或天)来调度作业.它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联. 整合了 Quartz.NET的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业. 官方学习文档:http://www.quartz-scheduler.net/documentation/index.html 使用实例介绍:ht

Quartz.Net任务统一调度框架

山寨版Quartz.Net任务统一调度框架 TaskScheduler 在日常工作中,大家都会经常遇到Win服务,在我工作的这些年中一直在使用Quartz.Net这个任务统一调度框架,也非常好用,配置简单,但是如果多个项目组的多个服务部署到一台服务器时还是不尽如人意. 这段时间很忙,也一直未更新博客了,赶上今天下班早,就研究了一下,弄了个简单版基于Timer的山寨Quartz,当然了只是实现任务调度,闲话少说直接入主题吧 一.技术准备 其实都是普通的微软技术,一想到这方我们第一想到的可能就是反射

异构云操作系统的集成与统一调度框架及调度方法

本发明公开的异构云操作系统的集成与统一调度框架,包括有资源收集模块.用户认证模块.统一调度模块及请求转化模块,资源收集模块.用户认证模块分别通过导线与统一调度模块连接,统一调度模块通过导线与请求转化模块连接,资源收集模块.请求转化模块分别通过导线与Elaster云操作系统.CloudStack操作系统及OpenStack操作系统连接.本发明还公开了上述集成与统一调度框架的调度方法.本发明的异构云操作系统的集成与统一调度框架解决了异构云操作之间资源无法共享,实现了对异构云操作系统的统一调度. 技术

开源调度框架Quartz最佳实践

开源调度框架Quartz最佳实践 Quartz是一个Java调度框架,当前的最新版本为2.2.1. 以Quartz 2.2.1版为例,Quartz最佳实践(用于生产系统)总结如下: 1.跳过更新检查Quartz内置了一个“更新检查”特性,因此Quartz项目每次启动后都会检查官网,Quartz是否存在新版本.这个检查是异步的,不影响Quartz项目本身的启动和初始化.可以在Quartz配置文件中,设置org.quartz.scheduler.skipUpdateCheck的属性为true来跳过更

分布式开源调度框架TBSchedule原理与应用

主要内容: 第一部分 TBSchedule基本概念及原理 1. 概念介绍 2. 工作原理 3. 源代码分析 4. 与其它开源调度框架对照 第二部分 TBSchedule分布式调度演示样例 1. TBSchedule源代码下载 2. 引入源代码Demo开发演示样例 3. 控制台配置任务调度 4. selectTasks方法參数说明 5. 创建调度策略參数说明 6. 创建任务參数说明 第一部分 TBSchedule基本概念及原理 1. 概念介绍 TBSchedule是一个支持分布式的调度框架.能让一

Quartz.Net 调度框架配置介绍

在平时的工作中,估计大多数都做过轮询调度的任务,比如定时轮询数据库同步,定时邮件通知等等.大家通过windows计划任务,windows服务等都实现过此类任务,甚至实现过自己的配置定制化的框架.那今天就来介绍个开源的调度框架Quartz.Net(主要介绍配置的实现,因为有朋友问过此类问题).调度的实现代码很简单,在源码中有大量Demo,这里就略过了. Quartz.Net当前最新版本 Quartz.NET 2.0 beta 1 Released 一 基于文件配置 先看一下简单的实现代码 usin