Quartz 框架是一个非常古老的框架,甚至可以说是其他定时框架(powerjod、xxl-job、scheduler)的始祖;其他框架要么是改造 quartz 而来、要么就是吸收 quartz 的核心思想而成。所以了解 quartz 的知识对使用其他框架很很大帮助,并且 quartz 的功能基本满足大部分场景。
具体任务的实现类。需要实现 org.quartz.Job 接口,具体的执行逻辑需要重写 execute 方法。
Job 的进一步封装。
触发器。任务实现的触发机制,包括定时任务的 cron 表达式就是在这里实现的。
调度器。会把 JobDetail 和 Trigger 结合在一起进行任务管理。
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class ScheduleJob implements Job{
@Override
public void execute(JobExecutionContext jobExecutionContext) {
JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
log.info("获取任务的一些其他信息:{}", jobDataMap);
log.info("这里书写需要执行的逻辑......");
}
}
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import quancheng.demo.quartz.job.ScheduleJob;
@Slf4j
@Configuration
public class QuartzConfig {
@Bean
public void config() throws SchedulerException {
Scheduler scheduler = new StdSchedulerFactory().getScheduler();
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class)
// 任务的唯一标识 key
.withIdentity(JobKey.jobKey("job1"))
// 带上任务的一些其他信息,方便后续处理使用
.usingJobData(new JobDataMap() {{
put("key1", "value1");
}})
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.withIdentity(TriggerKey.triggerKey("trigger1"))
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ? "))
.build();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}
}
上面的逻辑比较简单,实际使用的过程中会结合数据库和反射让定时任务去执行工程里面的其他服务。数据库表的设计这里不展开讲,一般核心都是 全类限定名+方法名 的形式,讲一下反射和springboot 工程的集成。
该类是一个非常普通的 service 类
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
public class ScheduleService {
public String job1() {
log.info("job1 start");
return "job1 end";
}
}
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Slf4j
@Component
public class ScheduleJob implements Job, ApplicationContextAware {
private static ApplicationContext context; // 需要实现 ApplicationContextAware 接口才能获取 spring 上下文实例
@SneakyThrows
@Override
public void execute(JobExecutionContext jobExecutionContext) {
String taskClass = "scheduleService"; //类名(不包含包名),且首字母需要小写,spring 管理类的方式就是首字母小写的类名。如果是通过数据库传入的全类限定名需要处理下。
String taskMethod = "job1";
Object object = context.getBean(taskClass); // 获取 spring 管理的类实例
Method m = object.getClass().getMethod(taskMethod);
String result = (String) m.invoke(object);
log.info("result:{}", result);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (ScheduleJob.context == null) {
ScheduleJob.context = applicationContext;
}
}
}
1.如果需要有管理任务的能力,需要使用调度器的(Scheduler )增删改查、暂停任务管理能力;另外注意使用单例管理 Scheduler 。
2.上述实现没有任务跟踪,需要设计一套任务执行跟踪体系,包括方法是否能执行、执行的结果、耗时等。
参考:
1.Spring Boot 集成Quartz的简单入门_springboot集成quartz_就看见扣扣号的博客-CSDN博客
2.SpringBoot2.0集成Quartz - 简书 (jianshu.com)
3.SpringBoot+Quartz+MySQL实现分布式定时任务 - 荒野猛兽 - 博客园 (cnblogs.com)