springboot配置不赘述
首先是Quartz的配置
@Configuration
public class QuartzConfig {
//定时任务调度工厂
@Autowired
private TaskSchedulerFactory myJobFactory;
@Bean
public SchedulerFactoryBean schedulerFactoryBean () {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean ();
schedulerFactoryBean.setJobFactory (myJobFactory);
return schedulerFactoryBean;
}
@Bean
public Scheduler scheduler () {
return schedulerFactoryBean ().getScheduler ();
}
}
其次调度工厂TaskSchedulerFactory
/**
* 定时任务调度工厂,实现spring自动注入
*/
@Component
public class TaskSchedulerFactory extends AdaptableJobFactory{
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
// 调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
// 进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
TaskSchedulerFactory中AutowireCapableBeanFactory 的作用可以使创建的JobDetail执行类进行自动注入
包装Scheduler创建TaskCronJobService定时任务服务类
@Service
public class TaskCronJobService {
@Autowired
private TimedTaskService timedTaskService;
@Autowired
private Scheduler scheduler;
/**
* 执行定时任务
*/
public int executeTask (TimedTask timedTask) {
JobKey jobKey = new JobKey (timedTask.getTaskId ().toString ());
TriggerKey triggerKey = new TriggerKey (timedTask.getTaskId ().toString ());
int index = 0;
try {
//查询触发器
Trigger trigger = scheduler.getTrigger(triggerKey);
//触发器存在则删除任务,确保定时任务的数据一致性
if(null != trigger){
scheduler.deleteJob (jobKey);
}
//创建新任务 如果定时任务是启用状态
if("0".equals (timedTask.getIsEnable ())){
Class < ? > jobClass = Class.forName (timedTask.getServiceUrl () + "." + timedTask.getServiceName ());
JobDetail jobDetail = JobBuilder.newJob ((Class < ? extends Job>) jobClass).withIdentity (jobKey)
.withDescription (timedTask.getTaskDesc ()).build ();
Trigger createTrigger=null;
//cron表达式执行的定时任务
if("0".equals (timedTask.getCycleExecution ())){
createTrigger = TriggerBuilder.newTrigger ().withIdentity(triggerKey).forJob (jobKey)
.withSchedule (CronScheduleBuilder.cronSchedule (timedTask.getCron ())
.withMisfireHandlingInstructionDoNothing ())
.build ();
}else{
//间隔时间执行的定时任务
int hour = (timedTask.getHour ()==null||timedTask.getHour ().isEmpty ())?0:Integer.parseInt (timedTask.getHour ());
int minute = (timedTask.getMinute ()==null||timedTask.getMinute ().isEmpty ())?0:Integer.parseInt (timedTask.getMinute ());
int second = (timedTask.getSecond ()==null||timedTask.getSecond ().isEmpty ())?0:Integer.parseInt (timedTask.getSecond ());
//计算时分秒之后得到的间隔秒数
int num = (hour*60*60)+(minute*60)+second;
createTrigger = TriggerBuilder.newTrigger ().withIdentity(triggerKey).forJob (jobKey)
.withSchedule (SimpleScheduleBuilder.repeatSecondlyForever(num)).build ();
}
jobDetail.getJobDataMap ().put ("taskId", timedTask.getTaskId ());
scheduler.scheduleJob(jobDetail, createTrigger);
}
//更新持久层的定时任务状态
timedTask.setStatus ("0");
//启动调度器 有时候运行没有问题但是定时任务不启动可能就是没有启动调度器
scheduler.start ();
} catch (Exception e) {
timedTask.setStatus ("2");
} finally {
index = updateTimedTask(timedTask);
}
//返回数据库受影响的行数
return index;
}
/**
* 暂停定时任务
*/
public int pauseTimedTask(Long taskId){
JobKey jobKey = new JobKey (taskId.toString ());
TimedTask timedTask = new TimedTask ();
timedTask.setTaskId (taskId);
timedTask.setIsEnable ("1");
timedTask.setStatus ("0");
try {
scheduler.pauseJob (jobKey);
} catch (SchedulerException e) {
timedTask.setStatus ("2");
}
//更新持久层的定时任务状态
return updateTimedTask (timedTask);
}
/**
* 删除定时任务
*/
public int deleteTimedTask(Long taskId){
JobKey jobKey = new JobKey (taskId.toString ());
TimedTask timedTask = new TimedTask ();
timedTask.setTaskId (taskId);
timedTask.setStatus ("-1");
try {
scheduler.deleteJob (jobKey);
} catch (SchedulerException e) {
}
//更新持久层的定时任务状态
return updateTimedTask (timedTask);
}
/**
* 重启定时任务
* 前台页面修改定时任务应该先走executeTask ()方法确保调度器中的定时任务数据和修改 后的定时任务数据一致,该方法只用于重启定时任务
*/
public int restartTimedTask(Long taskId){
JobKey jobKey = new JobKey (taskId.toString ());
TriggerKey triggerKey = new TriggerKey (taskId.toString ());
TimedTask tmp = new TimedTask ();
tmp.setTaskId (taskId);
tmp.setIsEnable ("0");
tmp.setStatus ("0");
try {
Trigger trigger = scheduler.getTrigger(triggerKey);
//如果没有该定时任务则直接创建
if(null == trigger){
TimedTask timedTask = timedTaskService.getTimedTaskForTaskId (taskId);
Class < ? > jobClass = Class.forName (timedTask.getServiceUrl () + "." + timedTask.getServiceName ());
JobDetail jobDetail = JobBuilder.newJob ((Class < ? extends Job>) jobClass).withIdentity (jobKey)
.withDescription (timedTask.getTaskDesc ()).build ();
Trigger createTrigger=null;
if("0".equals (timedTask.getCycleExecution ())){
createTrigger = TriggerBuilder.newTrigger ().withIdentity(triggerKey).forJob (jobKey)
.withSchedule (CronScheduleBuilder.cronSchedule (timedTask.getCron ())
.withMisfireHandlingInstructionDoNothing ())
.build ();
}else{
int hour = (timedTask.getHour ()==null||timedTask.getHour ().isEmpty ())?0:Integer.parseInt (timedTask.getHour ());
int minute = (timedTask.getMinute ()==null||timedTask.getMinute ().isEmpty ())?0:Integer.parseInt (timedTask.getMinute ());
int second = (timedTask.getSecond ()==null||timedTask.getSecond ().isEmpty ())?0:Integer.parseInt (timedTask.getSecond ());
int num = (hour*60*60)+(minute*60)+second;
createTrigger = TriggerBuilder.newTrigger ().withIdentity(triggerKey).forJob (jobKey)
.withSchedule (SimpleScheduleBuilder.repeatSecondlyForever(num)).build ();
}
jobDetail.getJobDataMap ().put ("taskId", timedTask.getTaskId ());
scheduler.scheduleJob(jobDetail, createTrigger);
}else{
//如果有该定时任务则直接重启
scheduler.resumeJob (jobKey);
}
} catch (Exception e) {
tmp.setStatus ("2");
}
return updateTimedTask (tmp);
}
/**
* 更新定时任务到数据库
* @param timedTask
*/
@Transactional
public int updateTimedTask(TimedTask timedTask){
return timedTaskService.updateTimedTask (timedTask);
}
}
最后是执行定时任务service
@Service
@DisallowConcurrentExecution//必须加该注解,否者会并发执行
public class TaskServiceImpl implements Job{
//如果没有TaskSchedulerFactory的配置,则该属性无法自动注入@Autowired注解无效
@Autowired
private TimedTaskService service;
@Override
public void execute (JobExecutionContext context) throws JobExecutionException {
//运行前更新状态为运行中
Long taskId = (Long) context.getJobDetail().getJobDataMap ().get ("taskId");
TimedTask timedTask = new TimedTask ();
timedTask.setStatus ("1");
timedTask.setTaskId (taskId);
service.updateTimedTask (timedTask);
try{
//业务代码
...
//运行完毕更新状态为未运行
timedTask.setStatus ("0");
}catch (Exception e) {
//运行出错更新状态为未运行
timedTask.setStatus ("2");
}finally {
service.updateTimedTask (timedTask);
}
}
}
最后补充一个启动任务,启动项目后从数据库扫描符合条件的定时任务,然后加载
/**
* 定时任务启动执行类,项目启动后扫描数据库加载定时任务
*/
@Component
@Order
public class TaskRunner implements ApplicationRunner{
@Autowired
private TimedTaskService timedTaskService;
@Autowired
private TaskCronJobService taskCronJobService;
@Override
public void run (ApplicationArguments args) throws Exception {
Map<String, Object> params = new HashMap <String, Object> ();
params.put ("isEnable", "0");
List <TimedTask> list = timedTaskService.getTimedTaskList (params, 0, 999999);
for (TimedTask timedTask : list) {
taskCronJobService.executeTask (timedTask);
}
}
}