通过Timer和Spring的scheduler实现定时任务可能会出现一旦定时任务中断后续的定时任务无法正常执行的问题,Quartz能够很好的解决这一问题。
项目使用Maven管理,因此在使用之前需要在pom文件中添加依赖,如下:
不要忘记spring-context-support。
紧接着需要添加Quartz配置类,我把代码粘贴了下来,如下:
其中需要import的部分内容:
import org.quartz.JobDetail;
import org.quartz.Trigger;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean;
-----------------------------------------------下边是配置类的实现-------------------------------------------------------
@Configuration
public class QuartzConfig
//指定了触发规则
@Bean(name = "firstTrigger")
public CornTriggerFactoryBean uploadTaskTrigger(JobDetail firstJobDetail){
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean();
trigger.setJobDetail(firstJobDetail);
trigger.setCronExpression("0 10 10 * * ?");//每天两点上传数据
return (CornTriggerFactoryBean) trigger;
}
@Bean(name = "firstJobDetail")
public MethodInvokingJobDetailFactoryBean uploadTaskDetail(){//指定了具体需要执行的类 具体的方法就是我们需要实现的excuteInternal
UploadTask uploadTask = (UploadTask)SpringUtil.getBean(UploadTask.class);
MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
// 是否并发执行
jobDetail.setConcurrent(false);
// 为需要执行的实体类对应的对象
jobDetail.setTargetObject(uploadTask);
// 需要执行的方法
jobDetail.setTargetMethod("task");
return jobDetail;
//return JobBuilder.newJob(UploadTask.class).withIdentity("uploadTask").storeDurably().build();
}
//第二个定时任务的触发规则
@Bean(name = "secondTrigger")
public SimpleTriggerFactoryBean submitFailDataTaskTrigger(JobDetail secondJobDetail){
SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean();
trigger.setJobDetail(secondJobDetail);
// 设置任务启动延迟
trigger.setStartDelay(0);
// 每5分钟执行一次
trigger.setRepeatInterval(300000);//300000
return trigger;
}
//第二个定时任务
@Bean(name = "secondJobDetail")
public MethodInvokingJobDetailFactoryBean SubmitFailedDataTaskDetail(){
SubmitFailedDataTask submitFailedDataTask = (SubmitFailedDataTask)SpringUtil.getBean(SubmitFailedDataTask.class);
MethodInvokingJobDetailFactoryBean jobDetail = new MethodInvokingJobDetailFactoryBean();
// 是否并发执行
jobDetail.setConcurrent(false);
// 为需要执行的实体类对应的对象
jobDetail.setTargetObject(submitFailedDataTask);
// 需要执行的方法
jobDetail.setTargetMethod("task");
return jobDetail;
//return JobBuilder.newJob(SubmitFailedDataTask.class).withIdentity("submitFailedDataTask").storeDurably().build();
}
// 配置Scheduler
@Bean(name = "scheduler")
public SchedulerFactoryBean schedulerFactory(Trigger firstTrigger, Trigger secondTrigger) {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
// 延时启动,应用启动1秒后
bean.setStartupDelay(1);
// 注册触发器
bean.setTriggers(firstTrigger, secondTrigger);
return bean;
}
}
其中,在配置Scheduler中注册两个触发器,然后项目启动1秒之后就会启动定时任务轮训,到了代码设置的corn表达式满足时,就会触发相应的定时任务。
需要注意的是上边拿到要执行的两个Task的时候定义了Util工具类,也就是SpringUtil工具类,代码如下:
其中需要import的内容如下:
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
实现类方法如下:
@Component
public class SpringUtil implements ApplicationContextAware{
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public static
return getApplicationContext().getBean(name, clazz);
}
}
然后去实现UploadTask和SubmitFailedDataTask两个定时任务就可以了
需要在任务实现类中实现task()方法
@DisallowConcurrentExecution
@EnableScheduling
@Component
public class UploadTask{
public void task(){ //task方法中实现主要逻辑就可以了。
}
}
最重要的是要在启动类中添加@EnableScheduling注解。
当前还是有一些比较疑惑的地方,后续也会整理一下,将来用得到的时候会方便一些。