在《Quartz任务调度(3)存储与持久化操作配置具体解析 》一文中,我们通过配置quartz.properties属性文件实现了Quartz的数据库持久化操作。如今整合spring的原理,就是相当于把我们在属性文件里的配置属性整合进SchedulerFactoryBean中。来生成我们的Scheduler类。
这里须要特别注意的是。我们通过Bean配置生成的JobDetail和CronTrigger或SimpleTrigger不能被序列化,因而不能持久化到数据库中,假设想要使用持久化任务调度,我们须要编程式创建Quartz的Job等相关实现类。
以下是我们的配置实例:
spring容器配置
<bean id="quartzDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" >
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://127.0.0.1:3306/quartz"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<!-- quartz持久化存储 -->
<bean name="quartzScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="dataSource">
<ref bean="quartzDataSource" />
</property>
<property name="applicationContextSchedulerContextKey" value="applicationContext" />
<property name="quartzProperties">
<props>
<!-- JobStore 配置 -->
<prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
<!-- 数据表设置 -->
<prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
<prop key="org.quartz.jobStore.dataSource">myDatadource</prop>
</props>
</property>
</bean>
在连接数据前,我们须要先在数据库中创建好相应的表格,在我開始提到的文章内有相关的sql语句。此外。关于quartzProperties还有非常多配置属性,如配置线程池、集群等。在我开头提到的那篇文章内都有具体说明。
測试类配置
package tool.job;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.ObjectAlreadyExistsException;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class pickNewsJob implements Job {
@Override
public void execute(JobExecutionContext jec) throws JobExecutionException {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
System.out.println("在" + sdf.format(new Date()) + "更新日志");
}
public static void main(String args[]) throws SchedulerException {
JobDetail jobDetail = JobBuilder.newJob(pickNewsJob.class)
.withIdentity("job1", "jgroup1").build();
SimpleTrigger simpleTrigger = TriggerBuilder
.newTrigger()
.withIdentity("trigger1")
.withSchedule(
SimpleScheduleBuilder
.repeatSecondlyForTotalCount(10, 2)).startNow()
.build();
try{
ApplicationContext ac = new ClassPathXmlApplicationContext("spring/spring-task.xml");
Scheduler scheduler = (Scheduler) ac.getBean("quartzScheduler");
scheduler.scheduleJob(jobDetail, simpleTrigger);
scheduler.start();
}catch ( ObjectAlreadyExistsException e) {
resumeJob();
}
}
/**
*依据数据库中的记录 恢复异常中断的任务
*/
public static void resumeJob() throws SchedulerException {
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
// ①获取调度器中全部的触发器组
List<String> triggerGroups = scheduler.getTriggerGroupNames();
// ②又一次恢复在tgroup1组中,名为trigger1触发器的执行
for (int i = 0; i < triggerGroups.size(); i++) {
List<String> triggers = scheduler.getTriggerGroupNames();
for (int j = 0; j < triggers.size(); j++) {
Trigger tg = scheduler.getTrigger(new TriggerKey(triggers
.get(j), triggerGroups.get(i)));
// ②-1:依据名称推断
if (tg instanceof SimpleTrigger
&& tg.getDescription().equals("jgroup1.DEFAULT")) {//因为我们之前測试没有设置触发器所在组,所以默觉得DEFAULT
// ②-1:恢复执行
scheduler.resumeJob(new JobKey(triggers.get(j),
triggerGroups.get(i)));
}
}
}
scheduler.start();
}
}
在这里,假设我们測试时在执行中断后再反复执行。会出现ObjectAlreadyExistsException异常。原因是我们创建的JobDetail和Trigger等的名字和数据库中已有记录冲突。新的任务尝试持久到数据库失败。在程序中。我的处理方法是先捕捉异常,然后调用恢复任务方法,来又一次执行异常中断的任务。
源代码下载
本例源代码可到我的github仓库https://github.com/jeanhao/spring的springQuartz目录下载