在网上查询资料,写写删删六七遍还是没怎么搞懂,最后还是写出来了,总结一下,确定是最简单的了。
为什么要使用quartz,而不用springboot的@Scheduled?
因为在日常的业务中,需要经常变换任务的执行时间,即cron的表达式,所以对于@Scheduled用来操作就有些麻烦了,而quartz就很好的可以封装成一个可修改的调用接口,方便业务的多变性
为什么要说一下思路,因为这个执行的顺序把我搞得很懵,所以只需要将这个思路搞清楚,就很容易的使用quartz的功能了,我简单描述一下我的这个思路
为业务层(eg: service)封装调用quartz的方法,该方法暴露执行的cron表达式(即第一步)
将业务层需要执行的作业放到quartz的执行方法中(即第二步)
springboot集成quartz,将quartz任务调度器跟随项目启动而启动起来(即第三步)
思路理顺了,业务的代码也就知道在哪里写了。
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
dependency>
<dependency>
<groupId>org.quartz-schedulergroupId>
<artifactId>quartzartifactId>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>4.12version>
dependency>
在业务层可以调用这个调度器,使用spring的注入@Autowired
package com.example.springboothtml.scheduler;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Component;
/**
* 调度器使用
*
* @author jiaohongtao
* @version 1.0
* @since 2020年11月04日
*/
@Slf4j
@Component
public class QuartzScheduler {
private static final String JOB_NAME = "inspect_report";
private static final String JOB_GROUP = "inspect_report_group";
private static final String TRIGGER_NAME = "inspect_report";
private static final String TRIGGER_GROUP = "inspect_report_group";
private static final String JOB_TASK_ID = "job_task_id";
/**
* quartz任务调度器
*/
@Autowired
private Scheduler scheduler;
/**
* 开始执行所有任务,并开启调度器
*
* @throws SchedulerException SchedulerException
*/
public void startJob() throws SchedulerException {
// 这里可以放一些初始化的任务,例如服务器宕机后,需要重新启动,如果没有不用考虑这个
// 步骤:1.创建一个新的 SchedulerJob 作业类,即第二步的代码
// 2.在这个类里写一个方法(invoke())调用新SchedulerJob的作业,然后将方法放到这里
scheduler.start();
}
public void add(int i, String cron) throws SchedulerException {
// 构建传递参数
JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put(JOB_TASK_ID, id);
jobDataMap.put("userId", userId);
JobDetail jobDetail = JobBuilder.newJob(InspectReportSchedulerJob.class).usingJobData(jobDataMap).
withIdentity(JOB_NAME + id, JOB_GROUP).build();
// 每5s执行一次
// String cron = "*/5 * * * * ?";
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron);
CronTrigger cronTrigger = TriggerBuilder.newTrigger().
withIdentity(TRIGGER_NAME + i, TRIGGER_GROUP).withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, cronTrigger);
}
public void remove(int i) throws SchedulerException {
boolean deleteJob = scheduler.deleteJob(new JobKey(JOB_NAME + i, JOB_GROUP));
log.info(deleteJob ? "任务移除成功" : "任务移除失败");
}
/**
* 初始注入scheduler
*
* @return scheduler
* @throws SchedulerException SchedulerException
*/
@Bean
public Scheduler scheduler() throws SchedulerException {
SchedulerFactory schedulerFactoryBean = new StdSchedulerFactory();
return schedulerFactoryBean.getScheduler();
}
}
将需要执行的业务放在放在execute方法中
package com.example.springboothtml.scheduler;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Date;
/**
* @author jiaohongtao
* @version 1.0
* @since 2020年11月04日
*/
@Slf4j
public class SchedulerJob implements Job {
private void before() {
System.out.println("任务开始执行");
}
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
before();
log.info(new Date() + ":我开始执行了......");
// TODO 业务
after();
}
private void after() {
System.out.println("任务结束执行");
}
}
这个类是在项目启动时,将quartz的任务调度器也拉起来,即第一步的里的方法 — quartzScheduler.startJob()
package com.example.springboothtml.scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
/**
* 启动服务后,开启调度器
*
* @author jiaohongtao
* @version 1.0
* @since 2020年11月04日
*/
@Configuration
public class QuartzStartListener implements ApplicationListener<ContextRefreshedEvent> {
@Autowired
private QuartzScheduler quartzScheduler;
@Override
public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {
try {
quartzScheduler.startJob();
System.out.println("*******quartz调度器启动*******");
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
package com.bocloud.inspect.service.util;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* cron表达式生成工具类
*
* @author jiaohongtao
* @version 1.0
* @since 2020年11月04日
*/
public class CronUtil {
/**
* 生成指定格式日期字符
*
* @param date 日期
* @param dateFormat : e.g:yyyy-MM-dd HH:mm:ss
* @return formatTimeStr
*/
public static String formatDateByPattern(Date date, String dateFormat) {
dateFormat = dateFormat == null ? "yyyy-MM-dd HH:mm:ss" : dateFormat;
SimpleDateFormat sdf = new SimpleDateFormat(dateFormat);
return date != null ? sdf.format(date) : null;
}
/**
* 生成cron表达式 ss mm HH dd MM ? yyyy
* convert Date to cron ,eg. "0 06 10 15 1 ? 2014"
*
* @param date : 时间点
*/
public static String getCron(Date date) {
String dateFormat = "ss mm HH dd MM ? yyyy";
return formatDateByPattern(date, dateFormat);
}
/**
* 生成cron表达式 ss mm HH dd MM ?
* convert Date to cron ,eg. "0 06 10 15 1 ?"
*
* @param date : 时间点
* @param type : 类型 日/周/月
*/
public static String getLoopCron(Date date, String type, Integer week, Integer day) {
String dateFormat = "ss mm HH";
// dd MM ?
String cron = formatDateByPattern(date, dateFormat);
switch (type) {
case "Day":
return cron + " * * ?";
case "Week":
return cron + " ? * " + getCurrentWeek(week);
case "Month":
return cron + " " + day + " * ?";
default:
return "false";
}
}
/**
* 获取当前星期的字符 MON TUE WED THU FRI SAT SUN
*
* @param week : 周 1 2 3 4 5 6 7
* @return 星期字符
*/
public static String getCurrentWeek(Integer week) {
String[] weeks = {"MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN"};
return weeks[week - 1];
}
public static void main(String[] args) {
Date date = new Date();
String dateFormat = "ss mm HH dd MM ? yyyy";
String cron = formatDateByPattern(date, dateFormat);
System.out.println("原始:" + cron);
String day = formatDateByPattern(date, "ss mm HH");
System.out.println("日报:" + day + " * * ?");
// 0 15 10 ? * MON 每周一上午10点15分
// 动参为 周
String week = formatDateByPattern(date, "ss mm HH");
System.out.println("周报:" + week + " ? * MON");
// 0 15 9 10 * ? 每月10号9点15分
// 动参为 号
String month = formatDateByPattern(date, "ss mm HH");
System.out.println("月报:" + month + " 10 * ?");
}
}
package com.example.springboothtml;
import com.example.springboothtml.scheduler.CronUtil;
import com.example.springboothtml.scheduler.QuartzScheduler;
import org.junit.Test;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author jiaohongtao
* @version 1.0
* @since 2020年11月04日
*/
@SpringBootTest
public class QuartzTest {
@Autowired
QuartzScheduler quartzScheduler;
@Test
public void test1() {
// Date date = new Date();
// String time = CronUtil.formatDateByPattern(date, null);
Date date = null;
try {
date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2020-11-04 17:25:30");
} catch (ParseException e) {
e.printStackTrace();
}
try {
quartzScheduler.add(1, CronUtil.getCron(date));
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}