Spring 和 Quartz 实现定时任务

时间:2022-09-26 23:26:17

注:文中示例和总结源自结尾的参考博客,感谢各位博主的分享

Quartz是一个开源的,用于处理定时任务的项目,因为相比于Java本身的Timer功能更强大一些,而且和Spring整合在了一起,所以应用广泛。我正好最近接触到的任务中碰到了它,做个记录

Java 定时的四种方式

  1. 使用Java自带的定时器Timer,自己实现TimerTask(抽象类,扩展了Runnable),传入Timer的方法中,进行调度,缺点是不能满足类似于“在某时某刻执行”的要求,另外可能出现定时不准,因为Timer是单线程的,所以就和JS的定时器一样,存在延迟
  2. 接着1说,改进是可以通过Java的线程池ScheduledThreadPoolExecutor来替代,可以指定多线程,消除定时不准的问题
  3. 使用Quartz,也就是本文接下来要讲的
  4. 使用Spring3.0后自带的Task,类似于Quartz,接下来也会介绍

Quartz

使用Quartz分两种:继承QuartzJobBean和不继承的,二者仅编写定时任务类和xml配置作业类两步不同
使用Quartz的一个注意点是:与Spring3.1以下版本整合必须使用Quartz1,因为Spring3.0版本以下,有一个类继承自Quartz1版本的类,在Quartz更高版本,那个类被改为接口了(见结尾参考博客:Spring与Quartz的整合实现定时任务调度

使用的步骤分为以下几个:

对于继承QuartzJobBean,需要做

1. 需要实现定时任务的类继承org.springframework.scheduling.quartz.QuartzJobBean,实现定时执行的方法,xml里要么声明这个定时任务类,要么使用注解扫描的方式声明

2. xml里声明新的bean,class为org.springframework.scheduling.quartz.JobDetailBean

描述定时任务类,例如:

<bean name="job" class="org.springframework.scheduling.quartz.JobDetailBean">  
<property name="jobClass" value="com.example.QuartzTimer" /> <!-- 这个属性,指定定时任务类 -->
<property name="jobDataAsMap"><!-- 这个属性,为定时任务类注入属性,注意对应定时任务类,需要有属性的set方法 -->
<map>
<entry key="timeout" value="0" />
</map>
</property>
</bean>

对于不继承,需要做

1. 需要实现定时任务的类,主要是实现定时执行的方法

2. xml里使用MethodInvokingJobDetailFactoryBean配置作业类,例如

<bean id="job" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">  
<property name="targetObject">
<bean class="com.example.QuartzTimer" /> <!-- 这个属性,指定定时任务类 -->
</property>
<property name="targetMethod" value="doJob" />
<property name="concurrent" value="false" /><!-- 作业不并发调度 -->
</bean>

接下来的三步,都一样

3. xml里配置触发器Trigger,用于指定什么时候执行定时任务

触发器分两种:org.springframework.scheduling.quartz.SimpleTriggerBeanorg.springframework.scheduling.quartz.CronTriggerBean。其中SimpleTriggerBean只支持按频率触发,比如每隔多长时间执行一次,而CronTriggerBean支持使用Cron表达式,指定类似“在每几天的什么时间执行”的触发

这里需要注意的是,触发器Trigger和定时任务的对应关系:一个触发器只能关联一个定时任务,但是一个定时任务可以关联多个触发器(定时任务类对触发器为多对一)
xml配置例如:

<!-- -->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="job" />
<property name="startDelay" value="0" /><!-- 调度工厂实例化后,经过0秒开始执行调度 -->
<property name="repeatInterval" value="2000" /><!-- 每2秒调度一次 -->
</bean>

<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="job" />
<!-- 每天12:00运行一次 -->
<property name="cronExpression" value="0 0 12 * * ?" />
</bean>

4. xml里配置调度工厂Scheduler,统一调度触发器的地方

<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
<property name="triggers"><!-- 所有的触发器配到这里,由调度工厂统一调度 -->
<list>
<ref bean="simpleTrigger"/>
<ref bean="cronTrigger" />
</list>
</property>
</bean>

最后,关于使用Quartz的最后一点,我们也可以继承TimerTask,实现定时任务的逻辑,然后通过xml里声明org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean,指向这个类,其他触发器调度工厂,配置不变的方式,实现定时任务。

使用Spring的Task

Spring引入注解后,很多功能都可以通过注解来配置完成了,当然xml的配置方式也保留了下来,Task也不例外
首先,不管xml方式还是注解方式,都需要在xml配置文件的文件头加入命名空间和描述

xml文件,文件头里新加入命名空间

xmlns:task="http://www.springframework.org/schema/task"

xsi:schemaLocation="http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-3.0.xsd

xml方式

1. 实现定时任务类,通过xml配置或者注解,声明这个类

2. 配置任务

 <task:scheduled-tasks>   
<!-- job为定时任务类,通过xml配置或者注解方式声明了得 -->
<task:scheduled ref="job" method="someMethod" cron="0 15 * * * ?"/>
</task:scheduled-tasks>

注解方式

1. 实现定时任务类,然后对方法加上Scheduled注解,里面还可配置cron表达式,或者固定延迟时间、固定频率

例如:

@Scheduled(cron = "0 0 3 * * ?")  
public void task() {
System.out.println(“任务进行中。。。”);
}

2. xml里配置task

<task:executor id="executor" pool-size="5" />  
<task:scheduler id="scheduler" pool-size="10" />
<!-- 开启这个配置,spring才能识别@Scheduled注解 -->
<task:annotation-driven executor="executor" scheduler="scheduler" />

参考博客

上述文档里的内容,其实是从三个博客里提出来的,感谢这三位博主的分享
1. Spring定时任务的几种实现
2. 使用Spring的@Scheduled实现定时任务
3. Spring与Quartz的整合实现定时任务调度