项目中需要用到定时任务,考虑了下java方面定时任务无非就三种:
鉴于项目有些地方要考虑动态管理定时任务的,所以考虑吧quartz也集成进去,方便调用。
一、首先引入依赖(必需)
org.quartz-scheduler
quartz
2.2.3
org.quartz-scheduler
quartz-jobs
2.2.3
二、创建job 实例工厂,解决spring注入问题,如果使用默认会导致spring的@Autowired 无法注入问题
package com.xjy.core.quartz.taskjobfactory;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
/**
* @author xujingyang
* @Description: 解决quartz无法注入spring bean问题
* @date 2018/5/30.
*/
@Component
public class TaskJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//调用父类的方法
Object jobInstance = super.createJobInstance(bundle);
//进行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
三、创建job管理类,对job进行增加,暂停,恢复,更新,删除等操作
package com.xjy.common.core.quartz.taskjobfactory;
import com.qunyi.jifenzhi_zx.common.core.quartz.BaseTaskJob;
import org.quartz.*;
import org.quartz.impl.matchers.GroupMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.*;
/**
* @author xujingyang
* @Description: task任务创建工具类
* @date 2018/5/30.
*/
@Component
public class QuartzJobManager {
private static final Logger logger = LoggerFactory.getLogger(QuartzJobManager.class);
private static QuartzJobManager jobUtil;
@Autowired
private Scheduler scheduler;
public QuartzJobManager() {
logger.info("init jobUtil");
jobUtil = this;
}
public static QuartzJobManager getInstance() {
logger.info("retun JobCreateUtil");
return QuartzJobManager.jobUtil;
}
/**
* 创建job
*
* @param clazz 任务类
* @param jobName 任务名称
* @param jobGroupName 任务所在组名称
* @param cronExpression cron表达式
* @throws Exception
* @author xujingyang
* @date 2018/5/30.
*/
public void addJob(Class clazz, String jobName, String jobGroupName, String cronExpression) throws Exception {
// 启动调度器
scheduler.start();
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(((BaseTaskJob) clazz.newInstance()).getClass()).withIdentity(jobName, jobGroupName).build();
//表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
.withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 创建job,可传参
*
* @param clazz 任务类
* @param jobName 任务名称
* @param jobGroupName 任务所在组名称
* @param cronExpression cron表达式
* @param argMap map形式参数
* @throws Exception
* @author xujingyang
* @date 2018/5/30.
*/
public void addJob(Class clazz, String jobName, String jobGroupName, String cronExpression, Map argMap) throws Exception {
// 启动调度器
scheduler.start();
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(((BaseTaskJob) clazz.newInstance()).getClass()).withIdentity(jobName, jobGroupName).build();
//表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)
.withSchedule(scheduleBuilder).build();
//获得JobDataMap,写入数据
trigger.getJobDataMap().putAll(argMap);
scheduler.scheduleJob(jobDetail, trigger);
}
/**
* 暂停job
*
* @param jobName 任务名称
* @param jobGroupName 任务所在组名称
* @throws SchedulerException
* @author xujingyang
* @date 2018/5/30.
*/
public void pauseJob(String jobName, String jobGroupName) throws SchedulerException {
scheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName));
}
/**
* 恢复job
*
* @param jobName 任务名称
* @param jobGroupName 任务所在组名称
* @throws SchedulerException
* @author xujingyang
* @date 2018/5/30.
*/
public void resumeJob(String jobName, String jobGroupName) throws SchedulerException {
scheduler.resumeJob(JobKey.jobKey(jobName, jobGroupName));
}
/**
* job 更新,只更新频率
*
* @param jobName 任务名称
* @param jobGroupName 任务所在组名称
* @param cronExpression cron表达式
* @throws Exception
* @author xujingyang
* @date 2018/5/30.
*/
public void updateJob(String jobName, String jobGroupName, String cronExpression) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
/**
* job 更新,更新频率和参数
*
* @param jobName 任务名称
* @param jobGroupName 任务所在组名称
* @param cronExpression cron表达式
* @param argMap 参数
* @throws Exception
* @author xujingyang
* @date 2018/5/30.
*/
public void updateJob(String jobName, String jobGroupName, String cronExpression, Map argMap) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
// 表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//修改map
trigger.getJobDataMap().putAll(argMap);
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
/**
* job 更新,只更新更新参数
*
* @param jobName 任务名称
* @param jobGroupName 任务所在组名称
* @param argMap 参数
* @throws Exception
* @author xujingyang
* @date 2018/5/30.
*/
public void updateJob(String jobName, String jobGroupName, Map argMap) throws Exception {
TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//修改map
trigger.getJobDataMap().putAll(argMap);
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
}
/**
* job 删除
*
* @param jobName 任务名称
* @param jobGroupName 任务所在组名称
* @throws Exception
* @author xujingyang
* @date 2018/5/30.
*/
public void deleteJob(String jobName, String jobGroupName) throws Exception {
scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, jobGroupName));
scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, jobGroupName));
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));
}
/**
* 启动所有定时任务
*
* @author xujingyang
* @date 2018/5/30.
*/
public void startAllJobs() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 关闭所有定时任务
*
* @author xujingyang
* @date 2018/5/30.
*/
public void shutdownAllJobs() {
try {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 获取所有任务列表
*
* @return
* @throws SchedulerException
*/
public List
四、增加quartz 属性配置文件 quartz.properties,放置resource目录下,此文件主要提供schedule自动注入提供属性
# 固定前缀org.quartz
org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false
五、创建quartz的配置文件QuartzrConfiguration,进行属性配置
package com.xjy.common.core.config;
import com.qunyi.jifenzhi_zx.common.core.quartz.taskjobfactory.TaskJobFactory;
import org.quartz.Scheduler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource;
import java.io.IOException;
/**
* @author xujingyang
* @Description: 任务调度配置
* @date 2018/5/30.
*/
@Configuration
public class QuartzConfigurer {
@Autowired
private DataSource dataSource;
@Autowired
private TaskJobFactory jobFactory;
@Bean(name = "SchedulerFactory")
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
//获取配置属性
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
//在quartz.properties中的属性被读取并注入后再初始化对象
propertiesFactoryBean.afterPropertiesSet();
//创建SchedulerFactoryBean
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setQuartzProperties(propertiesFactoryBean.getObject());
factory.setJobFactory(jobFactory);
return factory;
}
/*
* 通过SchedulerFactoryBean获取Scheduler的实例
*/
@Bean(name = "scheduler")
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
}
六、创建基础任务调度接口
package com.xjy.common.core.quartz;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
* @author xujingyang
* @Description: 基础任务调度taskJob接口,新建任务请继承此接口
* @date 2018/5/30
*/
public interface BaseTaskJob extends Job {
void execute(JobExecutionContext context)
throws JobExecutionException;
}
七、创建任务实现类
package com.qunyi.jifenzhi_zx.module.taskJob;
import com.qunyi.jifenzhi_zx.core.quartz.BaseTaskJob;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component
public class TestQuartz implements BaseTaskJob {
Logger logger = LoggerFactory.getLogger(this.getClass());
public int i = 0;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
i++;
logger.error("task2>>>>>>> " + i);
try {
// QuartzJobManager.getInstance().jobdelete(this.getClass().getSimpleName(),"ah");//执行完此任务就删除自己
} catch (Exception e) {
e.printStackTrace();
}
}
}
八、创建controller测试动态添加任务
@PostMapping("/task")
public void task(HttpServletRequest request) throws Exception {
String name = PrimaryKeyUtil.nextId();
QuartzJobManager.getInstance().addJob(TestQuartz.class, name, "*/1 * * * * ?");
}
九、访问测试结果
总结及注意:
这种任务执行时是整个类都要初始化一遍的,不像spring的schedule只初始执行方法,这种每次执行类中的变量都会初始化。
添加新任务调度时,只需要新建类然后继承任务接口实现方法即可,这样在添加任务的时候只需要传新建类的class就可以了。
传同一个class的时候,是同一个任务方法,只不过新建了开了一个线程来执行而已。