Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源的作业调度框架,它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz 允许开发人员根据时间间隔(或天)来调度作业。它实现了作业和触发器的多对多关系,还能把多个作业与不同的触发器关联。整合了 Quartz 的应用程序可以重用来自不同事件的作业,还可以为一个事件组合多个作业。
Quartz的应用场景
1.邮件提醒和告警
2.执行文件传输操作
3.创建销售报表
4.定时拉取银行对账文件,定时对账等
5.定时生成报表
...
Quartz框架的核心概念
scheduler: 任务调度器(可以调度多个trigger,可以包括不同类的trigger)
trigger: 触发器,用于定义任务调度时间规则(与job一一对应)
job: 任务,具体需要定时执行的方法
misfire: 错过的,指本来应该被执行但实际没有被执行的任务调度
job:
是一个接口,只有一个方法void execute(JobExecutionContext context),开发者实现该接口定义运行任务,JobExecutionContext类提供了调度上下文的各种信息。Job运行时的信息保存在JobDataMap实例中;JobDetail:
JobDetail承担描述Job的实现类及其它相关的静态信息,如Job名字、描述、关联监听器等信息JobDetail:
是一个类,描述触发Job执行的时间触发规则。有SimpleTrigger和CronTrigger这两个子类。
当需要在规定的时间执行一次或在规定的时间段以一定的时间间隔重复触发执行Job时,调度器选择org.springframework.scheduling.quartz.SimpleTriggerBean最好。SimpleTrigger的属性有:开始时间、结束时间、重复次数和重复的时间间隔,重复次数属性的值可以为0、正整数、或常量SimpleTrigger.REPEAT_INDEFINITELY,重复的时间间隔属性值必须为0或长整型的正整数,以毫秒作为时间单位,当重复的时 间间隔为0时,意味着与Trigger同时触发执行(或几乎与Scheduler开始时同时触发执行)。如果有指定结束时间属性值,则结束时间属性优先于重复次数属性,这样的好处在于:当我们需要创建一个每间隔10秒钟触发一次直到指定的结束时间的 Trigger,而无需去计算从开始到结束的所重复的次数,我们只需简单的指定结束时间和使用REPEAT_INDEFINITELY作为重复次数的属性 值即可(我们也可以指定一个比在指定结束时间到达时实际执行次数大的重复次数)。
CronTrigger则可以通过Cron表达式定义出各种复杂时间规则的调度方案:如每早晨9:00执行,周一、周三、周五下午5:00执行等;CronTrigger 支持类似日历的重复间隔,而不是单一的时间间隔。对应的调度器为org.springframework.scheduling.quartz.CronTriggerBean
- Scheduler :
代表一个Quartz的独立运行容器,Trigger和JobDetail可以注册到Scheduler中,两者在Scheduler中拥有各自的组及名称,组及名称是Scheduler查找定位容器中某一对象的依据,Trigger的组及名称必须唯一,JobDetail的组和名称也必须唯一(但可以和Trigger的组和名称相同,因为它们是不同类型的)。Scheduler定义了多个接口方法,允许外部通过组及名称访问和控制容器中Trigger和JobDetail。
Scheduler可以将Trigger绑定到某一JobDetail中,这样当Trigger触发时,对应的Job就被执行。一个Job可以对应多个Trigger,但一个Trigger只能对应一个Job。可以通过SchedulerFactory创建一个Scheduler实例。Scheduler拥有一个SchedulerContext,它类似于ServletContext,保存着Scheduler上下文信息,Job和Trigger都可以访问SchedulerContext内的信息。SchedulerContext内部通过一个Map,以键值对的方式维护这些上下文数据,SchedulerContext为保存和获取数据提供了多个put()和getXxx()的方法。可以通过Scheduler# getContext()获取对应的SchedulerContext实例;
关于Spring集成Quartz有2种方法:
JobDetailBean.
MethodInvokeJobDetailFactoryBean.
注意:在使用Spring集成Quartz的时候,一定不要忘记引入spring-support这个包
此处只讲第二种方法:MethodInvokeJobDetailFactoryBean方式
1.创建一个Job类,此类不需要继承任何类或者实现任何接口:
public class SpringQtz2 {
// 调用的方法
public void execute() {
// 需要做的事情
System.out.println("执行targetObject中的targetMethod方法,开始!");
System.out.println("执行targetObject中的targetMethod方法,结束!");
}
public static void main(String[] args) {
System.out.println("----begin---");
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring-config2.xml");
System.out.println(context);
// 如果配置文件中将SpringJobSchedulerFactoryBean bean的lazy-init设置为false 则不用实例化
context.getBean("SpringJobSchedulerFactoryBean");
2.配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.2.xsd"
default-lazy-init="true">
<!-- 方式二:使用MethodInvokingJobDetailFactoryBean,任务类可以不实现Job接口,通过targetMethod指定调用方法-->
<!-- 定义目标bean和bean中的方法 -->
<bean id="SpringQtzJob" class="com.zlh.hj.SpringQtz2"/>
<bean id="SpringQtzJobMethod" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="SpringQtzJob"/>
<property name="targetMethod" value="execute"/> <!-- 要执行的方法名称 -->
<!--将并发设置为false-->
<property name="concurrent" value="false" />
</bean>
<!-- ======================== CronTriggerBean调度触发器 ======================== -->
<bean id="CronTriggerBean" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="SpringQtzJobMethod"></property>
<property name="cronExpression" value="0/3 * * * * ?"></property>
</bean>
<!--======================== SimpleTriggerFactoryBean调度触发器 ======================== -->
<!-- <bean id="initSyncJob" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
<property name="jobDetail" ref="SpringQtzJobMethod"/>
<property name="repeatInterval">
<value>2000</value> 2秒调度一次
</property>
<property name="startDelay">
<value>0</value>
</property>
重复次数:0
去掉的话按结束时间算
<property name="repeatCount">
<value>0</value>
</property>
</bean> -->
<!-- ======================== 调度工厂 ======================== -->
<!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序 -->
<bean id="SpringJobSchedulerFactoryBean" autowire="no"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<!-- 此处可以有多个定时器 <ref bean=""/>-->
<ref bean="CronTriggerBean"/>
</list>
</property>
</bean>
</beans>
web.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<display-name>Spring_Quartz</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
</web-app>
最后运行main方法则控制台输出如下:
----begin---
org.springframework.context.support.ClassPathXmlApplicationContext@c4437c4: startup date [Sat May 20 15:56:07 CST 2017]; root of context hierarchy
----end---执行targetObject中的targetMethod方法,开始!
执行targetObject中的targetMethod方法,结束!
执行targetObject中的targetMethod方法,开始!
执行targetObject中的targetMethod方法,结束!
执行targetObject中的targetMethod方法,开始!
执行targetObject中的targetMethod方法,结束!
执行targetObject中的targetMethod方法,开始!
执行targetObject中的targetMethod方法,结束!
执行targetObject中的targetMethod方法,开始!
执行targetObject中的targetMethod方法,结束!
执行targetObject中的targetMethod方法,开始!
执行targetObject中的targetMethod方法,结束!
执行targetObject中的targetMethod方法,开始!
执行targetObject中的targetMethod方法,结束!