分享一篇关于Springboot整合Quartz任务框架在实际开发中的使用,基于SpringBoot2.0+Mybatis+Oracle开发
1. 导入jar包
<!-- 定时任务 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<!-- 其他的jar包请自行添加 -->
2. 配置任务调度器
@Configuration
public class ScheduleConfig {
/**
* 解决Job中注入Spring Bean为null的问题
*/
@Component("quartzJobFactory")
public static class QuartzJobFactory extends AdaptableJobFactory {
private final AutowireCapableBeanFactory capableBeanFactory;
public QuartzJobFactory(AutowireCapableBeanFactory capableBeanFactory) {
this.capableBeanFactory = capableBeanFactory;
}
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
/**
* 注入scheduler到spring
*/
@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;
}
}
3. 配置定时任务执行的方法
@Slf4j
@Component
public class ScheduleJob extends QuartzJobBean {
@Autowired
private SysQuartzLogService logService;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
SysQuartzLogEntity logs = new SysQuartzLogEntity();
// 执行时传入的任务信息
SysQuartzJobEntity job = (SysQuartzJobEntity) context.getMergedJobDataMap().get("JOB_PARAM_KEY");
// TODO 任务日志记录
logs.setBeanName(job.getBeanName());
logs.setCreateTime(new Date());
logs.setCronExpression(job.getCronExpression());
logs.setJobName(job.getJobName());
logs.setMethodName(job.getMethodName());
logs.setParams(job.getParams());
// 开始时间
Long startTime = System.currentTimeMillis();
try {
// 通过反射的方式去执行方法
// 获取需要执行的类实例
Object target = SpringContextUtils.getBean(job.getBeanName());
if (target != null) {
// 获取需要执行的方法
if (StringUtils.hasText(job.getParams())) {
Method method = target.getClass().getDeclaredMethod(job.getMethodName(), String.class);
// 执行方法
method.invoke(target, job.getParams());
} else {
Method method = target.getClass().getDeclaredMethod(job.getMethodName());
// 执行方法
method.invoke(target);
}
logs.setIsSuccess(0);
}
// 执行时长
Long time = System.currentTimeMillis() - startTime;
logs.setTime(String.valueOf(time));
} catch (Exception e) {
log.error("定时任务执行失败:{}", e);
logs.setIsSuccess(1);
logs.setExceptionDetail(e.getMessage());
Long time = System.currentTimeMillis() - startTime;
logs.setTime(String.valueOf(time));
// TODO 出现异常可以通过邮件进行通知
} finally {
// 保存任务执行的日志
logService.saveLog(logs);
}
}
}
4. 配置定时任务工具类
public class ScheduleUtils {
/**
* 任务名前缀
*/
public final static String JOB_NAME = "TASK_";
/**
* 分组名前缀
*/
public final static String JOB_GROUP = "GROUP_";
/**
* 获取触发器KEY
*/
public static TriggerKey getTriggerKey(String jobId) {
return TriggerKey.triggerKey(JOB_NAME + jobId, JOB_GROUP + jobId);
}
/**
* 获取job key
*/
public static JobKey getJobKey(String jobId) {
return JobKey.jobKey(JOB_NAME + jobId, JOB_GROUP + jobId);
}
/**
* 获取cron表达式的触发器
*/
public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {
try {
return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
} catch (SchedulerException e) {
throw new RuntimeException("获取定时任务CronTrigger出现异常", e);
}
}
/**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler, SysQuartzJobEntity job) {
try {
// 构建JOB信息
JobDetail detail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(job.getJobId())).build();
// Cron表达式调度器
CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule(job.getCronExpression()).withMisfireHandlingInstructionDoNothing();
// 按照新的cron创建新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(job.getJobId())).withSchedule(builder).build();
//放入参数,运行时的方法可以获取
detail.getJobDataMap().put(Constant.JOB_PARAM_KEY, job);
// 执行任务
scheduler.scheduleJob(detail, trigger);
// 暂停任务
if (job.getIsPause().equals(1)) {
pauseJob(scheduler, job);
}
} catch (Exception e) {
throw new RuntimeException("创建定时任务失败:{}", e);
}
}
/**
* 更新定时任务
*/
public static void updateScheduleJob(Scheduler scheduler, SysQuartzJobEntity job) {
try {
isHasJob(scheduler, job);
TriggerKey triggerKey = getTriggerKey(job.getJobId());
//表达式调度构建器
CronScheduleBuilder builder = CronScheduleBuilder.cronSchedule(job.getCronExpression()).withMisfireHandlingInstructionDoNothing();
CronTrigger trigger = getCronTrigger(scheduler, job.getJobId());
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(builder).build();
//放入参数,运行时的方法可以获取
trigger.getJobDataMap().put(Constant.JOB_PARAM_KEY, job);
scheduler.rescheduleJob(triggerKey, trigger);
//暂停任务(系统启动时调用此方法,需要判断任务的状态)
if (job.getIsPause().equals(1)) {
pauseJob(scheduler, job);
}
} catch (Exception e) {
throw new RuntimeException("更新定时任务失败", e);
}
}
/**
* 立即执行任务
*/
public static void run(Scheduler scheduler, SysQuartzJobEntity job) {
try {
isHasJob(scheduler, job);
//放入参数,运行时的方法可以获取
JobDataMap dataMap = new JobDataMap();
dataMap.put(Constant.JOB_PARAM_KEY, job);
scheduler.triggerJob(getJobKey(job.getJobId()), dataMap);
} catch (Exception e) {
throw new RuntimeException("定时任务执行失败", e);
}
}
/**
* 暂停任务
*/
public static void pauseJob(Scheduler scheduler, SysQuartzJobEntity job) {
try {
isHasJob(scheduler, job);
scheduler.pauseJob(getJobKey(job.getJobId()));
} catch (Exception e) {
throw new RuntimeException("定时任务暂停失败", e);
}
}
/**
* 恢复定时任务
*/
public static void resumeJob(Scheduler scheduler, SysQuartzJobEntity job) {
try {
isHasJob(scheduler, job);
scheduler.resumeJob(getJobKey(job.getJobId()));
} catch (Exception e) {
throw new RuntimeException("恢复定时任务失败", e);
}
}
/**
* 删除定时任务
*/
public static void deleteScheduleJob(Scheduler scheduler, SysQuartzJobEntity job) {
try {
scheduler.deleteJob(getJobKey(job.getJobId()));
} catch (Exception e) {
throw new RuntimeException("删除定时任务失败", e);
}
}
/**
* 判断是否存在任务
* 不存在则创建一个
*/
private static void isHasJob(Scheduler scheduler, SysQuartzJobEntity job) {
try {
CronTrigger cronTrigger = getCronTrigger(scheduler, job.getJobId());
if (cronTrigger == null) {
createScheduleJob(scheduler, job);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
5. 配置spring context 工具类
public class SpringContextUtils implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
}
sql
CREATE TABLE TS_SYS_QUARTZ_LOG
(
"LOG_ID" VARCHAR2(25) NOT NULL,
"BEAN_NAME" VARCHAR2(250) NOT NULL,
"CREATE_TIME" DATE DEFAULT sysdate NOT NULL,
"CRON_EXPRESSION" VARCHAR2(250) NOT NULL,
"EXCEPTION_DETAIL" VARCHAR2(250),
"IS_SUCCESS" NUMBER NOT NULL,
"JOB_NAME" VARCHAR2(250) NOT NULL,
"METHOD_NAME" VARCHAR2(250) NOT NULL,
"PARAMS" VARCHAR2(250),
"TIME" VARCHAR2(250) NOT NULL
);
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.LOG_ID IS '日志id';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.BEAN_NAME IS 'bean名称';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.CREATE_TIME IS '创建时间';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.CRON_EXPRESSION IS 'cron表达式';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.EXCEPTION_DETAIL IS '异常信息';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.IS_SUCCESS IS '是否成功,0-成功,1-失败';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.JOB_NAME IS 'JOB名称';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.METHOD_NAME IS '方法名';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.PARAMS IS '参数';
COMMENT ON COLUMN TS_SYS_QUARTZ_LOG.TIME IS '时间';
CREATE TABLE TS_SYS_QUARTZ_JOB
(
"JOB_ID" VARCHAR2(15) NOT NULL,
"BEAN_NAME" VARCHAR2(250) NOT NULL,
"CRON_EXPRESSION" VARCHAR2(250) NOT NULL,
"IS_PAUSE" NUMBER(1) DEFAULT 0 NOT NULL,
"JOB_NAME" VARCHAR2(250) NOT NULL,
"METHOD_NAME" VARCHAR2(250) NOT NULL,
"PARAMS" VARCHAR2(250),
"DESCRIPTION" VARCHAR2(250) NOT NULL,
"PERSON_IN_CHARGE" VARCHAR2(250) NOT NULL,
"EMAIL" VARCHAR2(250),
"SUB_TASK" VARCHAR2(250) NOT NULL,
"PAUSE_AFTER_FAILURE" NUMBER(2) NOT NULL,
"CREATE_BY" VARCHAR2(250) NOT NULL,
"UPDATE_BY" VARCHAR2(250),
"CREATE_TIME" DATE DEFAULT sysdate NOT NULL,
"UPDATE_TIME" DATE
);
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.JOB_ID IS 'ID';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.BEAN_NAME IS 'Spring Bean名称';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.CRON_EXPRESSION IS 'cron 表达式';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.IS_PAUSE IS '状态,0-执行,1-暂停,2-删除';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.JOB_NAME IS '任务名称';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.METHOD_NAME IS '方法名称';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.PARAMS IS '参数';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.DESCRIPTION IS '备注';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.PERSON_IN_CHARGE IS '负责人';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.EMAIL IS '报警邮箱';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.SUB_TASK IS '子任务ID';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.PAUSE_AFTER_FAILURE IS '任务失败后是否暂停';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.CREATE_BY IS '创建者';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.UPDATE_BY IS '更新者';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.CREATE_TIME IS '创建日期';
COMMENT ON COLUMN TS_SYS_QUARTZ_JOB.UPDATE_TIME IS '更新时间';