简单的定时任务用 spring的 @Scheduled 注解即可
@Component
public class ScheduledTask {
@Scheduled(fixedRate = 5000)
//表示每隔5000ms,Spring scheduling会调用一次该方法,不论该方法的执行时间是多少
public void reportCurrentTime() throws InterruptedException {
System.out.println(new Date()));
}
@Scheduled(fixedDelay = 5000)
//表示当方法执行完毕5000ms后,Spring scheduling会再次调用该方法
public void reportCurrentTimeAfterSleep() throws InterruptedException {
System.out.println(new Date()));
}
@Scheduled(cron = "0 0 1 * * *")
//提供了一种通用的定时任务表达式,这里表示每隔5秒执行一次,更加详细的信息可以参考cron表达式。
public void reportCurrentTimeCron() throws InterruptedException {
System.out.println(new Date()));
}
}
复制代码
- 运行类
@SpringBootApplication
@EnableScheduling
//告诉Spring创建一个task executor,如果我们没有这个标注,所有@Scheduled标注都不会执行
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
复制代码
Quartz 实现动态设置定时任务
- 官网:http://www.quartz-scheduler.org/
- 实战
首先需要一个配置类
package com.*.myquartz;
import org.quartz.Scheduler;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
/**
* @Author by xup .
* @Descriptions
* @Datetime in 2018/1/30 17:07.
*/
@Configuration
public class QuartzConfiguration {
//解决Job中注入Spring Bean为null的问题
@Component("quartzJobFactory")
private class QuartzJobFactory extends AdaptableJobFactory {
//这个对象Spring会帮我们自动注入进来,也属于Spring技术范畴.
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入,这属于Spring的技术,不清楚的可以查看Spring的API.
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
//注入scheduler到spring,在下面quartzManege会用到
@Bean(name = "scheduler")
public Scheduler scheduler(QuartzJobFactory quartzJobFactory) throws Exception {
SchedulerFactoryBean factoryBean=new SchedulerFactoryBean();
factoryBean.setJobFactory(quartzJobFactory);
factoryBean.afterPropertiesSet();
Scheduler scheduler=factoryBean.getScheduler();
scheduler.start();
return scheduler;
}
}
复制代码
还需要quartz 用到的实体类
package com.*.myquartz;
import lombok.Data;
/**
* @author xup
* @since 2018-01-29
*/
@Data
public class QuartzJob {
public static final Integer STATUS_RUNNING = 1;
public static final Integer STATUS_NOT_RUNNING = 0;
public static final Integer CONCURRENT_IS = 1;
public static final Integer CONCURRENT_NOT = 0;
private String jobId;
/**
* cron 表达式
*/
private String cronExpression;
/**
* 任务调用的方法名
*/
private String methodName;
/**
* 任务是否有状态
*/
private Integer isConcurrent;
/**
* 描述
*/
private String description;
/**
* 任务执行时调用哪个类的方法 包名+类名,完全限定名
*/
private String beanName;
/**
* 触发器名称
*/
private String triggerName;
/**
* 任务状态
*/
private Integer jobStatus;
private String springBean;
/**
* 任务名
*/
private String jobName;
}
复制代码
接着是任务管理类
根据传入quartzJob 类参数决定调用那个类的定时任务方法 与上面介绍的简单schedule更灵活。可实现不修改配置文件来开启和停用定时任务,无需重启项目
package com.*.myquartz;
import org.quartz.*;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;
/**
* @Author by xup .
* @Descriptions
* @Datetime in 2018/1/30 17:20.
*/
@Component
public class QuartzManage {
@Resource(name = "scheduler")
private Scheduler scheduler;
public void addJob(QuartzJob job) throws SchedulerException, ClassNotFoundException, IllegalAccessException, InstantiationException {
//通过类名获取实体类,即要执行的定时任务的类
Class<?> clazz = Class.forName(job.getBeanName());
Job jobEntity = (Job)clazz.newInstance();
//通过实体类和任务名创建 JobDetail
JobDetail jobDetail = newJob(jobEntity.getClass())
.withIdentity(job.getJobName()).build();
//通过触发器名和cron 表达式创建 Trigger
Trigger cronTrigger = newTrigger()
.withIdentity(job.getTriggerName())
.startNow()
.withSchedule(CronScheduleBuilder.cronSchedule(job.getCronExpression()))
.build();
//执行定时任务
scheduler.scheduleJob(jobDetail,cronTrigger);
}
/**
* 更新job cron表达式
* @param quartzJob
* @throws SchedulerException
*/
public void updateJobCron(QuartzJob quartzJob) throws SchedulerException {
TriggerKey triggerKey = TriggerKey.triggerKey(quartzJob.getJobName());
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(quartzJob.getCronExpression());
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
}
/**
* 删除一个job
* @param quartzJob
* @throws SchedulerException
*/
public void deleteJob(QuartzJob quartzJob) throws SchedulerException {
JobKey jobKey = JobKey.jobKey(quartzJob.getJobName());
scheduler.deleteJob(jobKey);
}
/**
* 恢复一个job
* @param quartzJob
* @throws SchedulerException
*/
public void resumeJob(QuartzJob quartzJob) throws SchedulerException {
JobKey jobKey = JobKey.jobKey(quartzJob.getJobName());
scheduler.resumeJob(jobKey);
}
/**
* 立即执行job
* @param quartzJob
* @throws SchedulerException
*/
public void runAJobNow(QuartzJob quartzJob) throws SchedulerException {
JobKey jobKey = JobKey.jobKey(quartzJob.getJobName());
scheduler.triggerJob(jobKey);
}
/**
* 暂停一个job
* @param quartzJob
* @throws SchedulerException
*/
public void pauseJob(QuartzJob quartzJob) throws SchedulerException {
JobKey jobKey = JobKey.jobKey(quartzJob.getJobName());
scheduler.pauseJob(jobKey);
}
}
复制代码
最后是测试类
注意:定时任务必须实现Job接口, 然后将定时任务的方法放入execute()方法中即可
package com.*.myquartz;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
@Slf4j
public class TaskTest implements Job {
public void run() {
for (int i = 0; i < 10; i++) {
log.info(i+" run ################## " + (new Date()));
}
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
run();
}
}
复制代码
后台管理界面,可随时开启,停用定时任务
接入业务逻辑实现数据库同步
这里的实体类(针对数据库)和quartz中的实体类(针对quartz)需要做一下转换,当然他们的字段可以完全一致
@Autowired
private QuartzManage quartzManage;
@Autowired
private ScheduleJobDao scheduleJobDao;
//这里添加定时任务时,默认是不开启的,需要手动执行开启,暂停任务
@Override
public ResultData<Boolean> addScheduleJob(ScheduleJobForm scheduleJobForm) {
if (!CronExpression.isValidExpression(scheduleJobForm.getCronExpression())){
return new ResultData<>(ResultMsg.ERROR,"cron表达式格式错误!");
}
return new ResultData<>(add(scheduleJobForm));
}
//开启或暂停定时任务
@Override
public boolean changeJobStatus(ScheduleJobForm scheduleJobForm) throws SchedulerException, IllegalAccessException, InstantiationException, ClassNotFoundException {
ScheduleJobForm oldJob = scheduleJobDao.selectById(scheduleJobForm.getJobId());
oldJob.setJobStatus(scheduleJobForm.getJobStatus());
if (XpObjectUtil.equals(scheduleJobForm.getJobStatus(), QuartzJob.STATUS_RUNNING)){
quartzManage.addJob(QuartzJobUtils.entityToData(oldJob));
} else if (XpObjectUtil.equals(scheduleJobForm.getJobStatus(), QuartzJob.STATUS_NOT_RUNNING)) {
quartzManage.deleteJob(QuartzJobUtils.entityToData(oldJob));
}
scheduleJobForm.setUpdateBy(SecurityUtil.getCurrUserAccount());
return editById(scheduleJobForm);
}
复制代码
- 这里还有个问题,项目重启时所有运行的定时任务会被销毁
下面的操作即为项目启动时重新载入启用状态的定时任务
这时实现 ApplicationRunner接口 重写run方法即可 项目启动时会执行run方法里的操作
package com.*.myquartz;
import com.*.enums.DataStatus;
import com.*.task.schedule.form.ScheduleJobForm;
import com.*.task.schedule.service.ScheduleJobService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @Author by xup .
* @Descriptions
* @Datetime in 2018/1/31 11:41.
*/
@Component
@Slf4j
public class MyApplicationRunner implements ApplicationRunner {
@Autowired
private ScheduleJobService scheduleJobService;
@Override
//项目启动时重新激活启用的定时任务
public void run(ApplicationArguments applicationArguments) throws Exception {
ScheduleJobForm scheduleJobForm = new ScheduleJobForm();
scheduleJobForm.setDeleteFlag(DataStatus.DEFAULT.getStatus());
scheduleJobForm.setJobStatus(1);
List<ScheduleJobForm> scheduleJobList = scheduleJobService.selectList(scheduleJobForm);
log.info("##########################"+scheduleJobList.size());
if (CollectionUtils.isNotEmpty(scheduleJobList)){
scheduleJobService.initScheduleJob(scheduleJobList);
}
}
}
复制代码
到此一个完整的定时任务管理模块完成了