本文主要是针对springboot 整合quartz 来说明,作为一个小白我总喜欢上网查找资料,然后希望找的东西能80%符合自己的需求,能直接拿来用的,但是很多时候网上的案例都是一个copy一个的,看的东西千篇一律,而且有些内容解释的也是寥寥数语,所以有时候也需要自己写点东西分享给大众,今天也是自己刚申请csdn ,取的笔名为:随笔发烧友,励志自己后面能多写文章,乐在分享。好了,进入正题吧!
Quartz
quartz是一个java编写的开源任务调度框架其主要调度元素有:
- Trigger(触发器):触发任务任务执行的时间或规则。在任务调度Quartz中,Trigger主要的触发器有:SimpleTrigger,CalendarIntervelTrigger,DailyTimeIntervalTrigger,CronTrigger
- Scheduler(任务调度器):Scheduler就是任务调度控制器,需要把JobDetail和Trigger注册到schedule中,才可以执行 ;Scheduler有两个重要组件:ThreadPool和JobStore。
- Job(任务):是一个接口,其中只有一个execute方法。开发者只要实现接口中的execute方法即可。
- JobDetail(任务细节):Quartz执行Job时,需要新建Job实例,但不能直接操作Job类,所以通过JobDetail获得Job的名称,描述信息。
先了解quartz四大要素,然后我们的目的就是组合四大要素,实现任务的创建,并启用/暂停/移除/更新操作
1、编写一个自己要实现的任务类,实现Job接口中的执行方法 execute
/**
* 定时任务实现类
*/
@Configuration
@Component
@EnableScheduling
public class ScheduleTask1 implements Job {
private static Logger logger = LoggerFactory.getLogger(ScheduleTask1.class);
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
try {
System.out.print("任务执行1 :");
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()));
} catch (Exception e) {
logger.error(e.getMessage());
}
}
2、构建任务细节
@Service
public class TaskService {
@SuppressWarnings("unused")
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Autowired
private QuartzJobRepository repository;
/**
* 获取单个任务
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public QuartzJobBean getJob(String jobName,String jobGroup) throws SchedulerException {
QuartzJobBean job = null;
Scheduler scheduler = getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (null != trigger) {
job = createJob(jobName, jobGroup, scheduler, trigger);
}
return job;
}
private Scheduler getScheduler() {
return schedulerFactoryBean.getScheduler();
}
private QuartzJobBean createJob(String jobName, String jobGroup, Scheduler scheduler, Trigger trigger)
throws SchedulerException {
QuartzJobBean job;
job = new QuartzJobBean();
job.setJobName(jobName);
job.setJobGroup(jobGroup);
job.setDescription("触发器:" + trigger.getKey());
job.setNextTime(trigger.getNextFireTime());
job.setPreviousTime(trigger.getPreviousFireTime());
Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
job.setJobStatus(triggerState.name());
if(trigger instanceof CronTrigger) {
CronTrigger cronTrigger = (CronTrigger)trigger;
String cronExpression = cronTrigger.getCronExpression();
job.setCronExpression(cronExpression);
}
return job;
}
/**
* 获取所有任务
* @return
* @throws SchedulerException
*/
public List<QuartzJobBean> getAllJobs() throws SchedulerException{
Scheduler scheduler = getScheduler();
GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
List<QuartzJobBean> jobList = new ArrayList<QuartzJobBean>();
List<? extends Trigger> triggers;
QuartzJobBean job;
for (JobKey jobKey : jobKeys) {
triggers = scheduler.getTriggersOfJob(jobKey);
for (Trigger trigger : triggers) {
job = createJob(jobKey.getName(), jobKey.getGroup(), scheduler, trigger);
jobList.add(job);
}
}
return jobList;
}
/**
* 所有正在运行的job
*
* @return
* @throws SchedulerException
*/
public List<QuartzJobBean> getRunningJob() throws SchedulerException {
Scheduler scheduler = getScheduler();
List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
List<QuartzJobBean> jobList = new ArrayList<QuartzJobBean>(executingJobs.size());
QuartzJobBean job;
JobDetail jobDetail;
JobKey jobKey;
for (JobExecutionContext executingJob : executingJobs) {
jobDetail = executingJob.getJobDetail();
jobKey = jobDetail.getKey();
job = createJob(jobKey.getName(), jobKey.getGroup(), scheduler, executingJob.getTrigger());
jobList.add(job);
}
return jobList;
}
/**
* 添加任务
*
* @param scheduleJob
* @throws SchedulerException
*/
public boolean addJob(QuartzJobBean job) throws SchedulerException {
if(job == null || !QuartzJobBean.STATUS_RUNNING.equals(job.getJobStatus())) {
return false;
}
String jobName = job.getJobName();
String jobGroup = job.getJobGroup();
if(!TaskUtils.isValidExpression(job.getCronExpression())) {
logger.error("时间表达式错误("+jobName+","+jobGroup+"), "+job.getCronExpression());
return false;
} else {
Scheduler scheduler = getScheduler();
// 任务名称和任务组设置规则: // 名称:task_1 .. // 组 :group_1 ..
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroup);
Trigger trigger = scheduler.getTrigger(triggerKey);
// 不存在,创建一个
if (null == trigger) {
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
// 按新的表达式构建一个新的trigger
trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
.startAt(job.getStartTime()==null ? (new Date()) : job.getStartTime()) // 设置job不早于这个时间进行运行,和调用trigger的setStartTime方法效果一致
.withSchedule(scheduleBuilder).build();
//是否允许并发执行
JobDetail jobDetail = getJobDetail(job);
// 将 job 信息存入数据库
job.setStartTime(trigger.getStartTime());
job.setNextTime(trigger.getNextFireTime());
job.setPreviousTime(trigger.getPreviousFireTime());
job = repository.save(job);
jobDetail.getJobDataMap().put(getJobIdentity(job), job);
scheduler.scheduleJob(jobDetail, trigger);
} else { // trigger已存在,则更新相应的定时设置
// 更新 job 信息到数据库
job.setStartTime(trigger.getStartTime());
job.setNextTime(trigger.getNextFireTime());
job.setPreviousTime(trigger.getPreviousFireTime());
job = repository.save(job);
getJobDetail(job).getJobDataMap().put(getJobIdentity(job), job);
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
// 按新的表达式构建一个新的trigger
trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
.startAt(job.getStartTime()==null ? (new Date()) : job.getStartTime()) // 设置job不早于这个时间进行运行,和调用trigger的setStartTime方法效果一致
.withSchedule(scheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
}
}
return true;
}
private String getJobIdentity(QuartzJobBean job) {
return "scheduleJob"+(job.getJobGroup() +"_"+job.getJobName());
}
private JobDetail getJobDetail(QuartzJobBean job) {
Class<? extends Job> clazz = QuartzJobBean.CONCURRENT_IS.equals(job.isConcurrent())
? QuartzJobFactory.class : QuartzJobFactoryDisallowConcurrentExecution.class;
JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build();
return jobDetail;
}
/**
* 暂停任务
* @param job
* @return
*/
@Transactional
public boolean pauseJob(QuartzJobBean job){
Scheduler scheduler = getScheduler();
JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
boolean result;
try {
scheduler.pauseJob(jobKey);
// 更新任务状态到数据库
job.setJobStatus(QuartzJobBean.STATUS_NOT_RUNNING);
repository.modifyByStatus(job.getJobStatus(), job.getJobId());
result = true;
} catch (SchedulerException e) {
result = false;
e.printStackTrace();
}
return result;
}
/**
* 恢复任务
* @param job
* @return
*/
@Transactional
public boolean resumeJob(QuartzJobBean job){
Scheduler scheduler = getScheduler();
JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
boolean result;
try {
logger.info("resume job : " + (job.getJobGroup() + "_" + job.getJobName()));
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
.startAt(job.getStartTime()==null ? (new Date()) : job.getStartTime()) // 设置job不早于这个时间进行运行,和调用trigger的setStartTime方法效果一致
.withSchedule(scheduleBuilder).build();
scheduler.rescheduleJob(triggerKey, trigger);
scheduler.resumeJob(jobKey);
// 更新任务状态到数据库
job.setJobStatus(QuartzJobBean.STATUS_RUNNING);
repository.modifyByStatus(job.getJobStatus(), job.getJobId());
result = true;
} catch (SchedulerException e) {
result = false;
e.printStackTrace();
}
return result;
}
/**
* 删除任务
*/
@Transactional
public boolean deleteJob(QuartzJobBean job){
Scheduler scheduler = getScheduler();
JobKey jobKey = JobKey.jobKey(job.getJobName(), job.getJobGroup());
boolean result;
try{
scheduler.deleteJob(jobKey);
// 更新任务状态到数据库
job.setJobStatus(QuartzJobBean.STATUS_DELETED);
repository.modifyByStatus(job.getJobStatus(), job.getJobId());
result = true;
} catch (SchedulerException e) {
result = false;
e.printStackTrace();
}
return result;
}
/**
* 立即执行一个任务
* @param scheduleJob
* @throws SchedulerException
*/
public void startJob(QuartzJobBean scheduleJob) throws SchedulerException{
Scheduler scheduler = getScheduler();
JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup());
scheduler.triggerJob(jobKey);
}
/**
* 更新任务时间表达式
* @param job
* @throws SchedulerException
*/
@Transactional
public void updateCronExpression(QuartzJobBean job) throws SchedulerException {
Scheduler scheduler = getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
//获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
// 更新 job 信息到数据库
job.setStartTime(trigger.getStartTime());
job.setNextTime(trigger.getNextFireTime());
job.setPreviousTime(trigger.getPreviousFireTime());
job = repository.save(job);
getJobDetail(job).getJobDataMap().put(getJobIdentity(job), job);
}
/**
* 设置job的开始schedule时间
* @param job
* @throws SchedulerException
*/
@Transactional
public void updateStartTime(QuartzJobBean job) throws SchedulerException {
Scheduler scheduler = getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup());
//获取trigger,即在spring配置文件中定义的 bean id="myTrigger"
CronTriggerImpl trigger = (CronTriggerImpl) scheduler.getTrigger(triggerKey);
trigger.setStartTime(job.getStartTime());
//按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
// 更新 job 信息到数据库
job.setStartTime(trigger.getStartTime());
job.setNextTime(trigger.getNextFireTime());
job.setPreviousTime(trigger.getPreviousFireTime());
job = repository.save(job);
getJobDetail(job).getJobDataMap().put(getJobIdentity(job), job);
}
}
服务启动时,读取数据库 job 信息,并进行 schedule
@Component
public class MyRunner implements CommandLineRunner {
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private TaskService taskService;
@Autowired
private QuartzJobService jobService;
@Override
public void run(String... args) throws Exception {
// 可执行的任务列表
List<QuartzJobBean> taskList = jobService.findByJobStatus(QuartzJobBean.STATUS_RUNNING);
logger.info("初始化加载定时任务......");
for (QuartzJobBean job : taskList) {
try {
taskService.addJob(job);
} catch (Exception e) {
logger.error("add job error: " + job.getJobName() + " " + job.getJobGroup(), e);
}
}
}
}