效果图主要功能功能实现使用方法原理总结 1.效果图(前端做的太low,所以结合了swagger2框架调试接口) 1.1:页面效果图 1.2:接口文档图: 2.主要功能
- 定时任务状态的启动、停止、恢复、立即执行一次。定时任务执行周期的动态修改。定时任务的增删改。
CREATE TABLE `job` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id', `job_name` varchar(255) NOT NULL COMMENT '任务名称', `job_group` varchar(255) NOT NULL COMMENT '任务组名', `status` int(255) NOT NULL COMMENT '任务状态:0=正常,1=暂停', `trigger_name` varchar(255) NOT NULL COMMENT 'trigger名称', `trigger_group` varchar(255) NOT NULL COMMENT 'trigger组名', `invoke_target` varchar(255) NOT NULL COMMENT '调用目标字符串', `concurrent` varchar(255) NOT NULL COMMENT '并发执行 0=允许,1=禁止', `cron_expression` varchar(255) NOT NULL COMMENT 'cron执行表达式', `misfire_policy` varchar(255) NOT NULL COMMENT '计划策略 0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行', `create_time` datetime DEFAULT NULL COMMENT '创建时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4;3.2:添加依赖
(项目是使用springboot构建,以下只展示主要用到的依赖)
org.quartz-scheduler
quartz
2.3.2
org.springframework
spring-context-support
5.3.12
commons-io
commons-io
2.6
org.apache.commons
commons-lang3
3.10
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2
com.github.xiaoymin
swagger-bootstrap-ui
1.9.6
3.2:代码实现
省略Controller、mapper、实体类和接口代码
3.2.1: 任务调度通用常量代码public class ScheduleConstants {
public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
public static final String MISFIRE_DEFAULT = "0";
public static final String MISFIRE_IGNORE_MISFIRES = "1";
public static final String MISFIRE_FIRE_AND_PROCEED = "2";
public static final String MISFIRE_DO_NOTHING = "3";
}
3.2.2: 调用quartz抽象类
public abstract class AbstractQuartzJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
MyJob myJob = new MyJob();
copyBeanProp(myJob, jobExecutionContext.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
try {
//执行定时任务
doExecute(jobExecutionContext,myJob);
} catch (Exception e) {
e.printStackTrace();
}
}
protected abstract void doExecute(JobExecutionContext context, MyJob myJob) throws Exception;
public static void copyBeanProp(Object dest, Object src) {
try {
copyProperties(src, dest);
} catch (Exception e) {
e.printStackTrace();
}
}
}
3.2.3: job任务类
Job任务累分为俩种:允许并发执行和禁止并非执行
@DisallowConcurrentExecution
public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
{
@Override
protected void doExecute(JobExecutionContext context, MyJob job) throws Exception
{
JobInvokeUtil.invokeMethod(job);
}
}
public class QuartzJobExecution extends AbstractQuartzJob
{
@Override
protected void doExecute(JobExecutionContext context, MyJob myJob) throws Exception
{
JobInvokeUtil.invokeMethod(myJob);
}
}
3.2.4: Spring工具类
@Component
public final class SpringUtils implements BeanFactoryPostProcessor{
private static ConfigurableListableBeanFactory beanFactory;
@SuppressWarnings("unchecked")
public static T getBean(String name) throws BeansException {
return (T) beanFactory.getBean(name);
}
3.2.5: 任务执行工具工具类
public class JobInvokeUtil {
private static void invokeMethod(Object bean, String methodName, List
3.2.6: Schedule工具类
public class ScheduleUtil {
private static Class extends Job> getQuartzJobClass(MyJob myJob) {
boolean isConcurrent = "0".equals(myJob.getConcurrent());
return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
}
public static void intSchedule(Scheduler scheduler, MyJob myJob) throws Exception {
//1.创建JobDetail
JobDetail jobDetail = JobBuilder.newJob(getQuartzJobClass(myJob))
.withIdentity(getJobKey(myJob.getId(), myJob.getJobGroup()))
.build();
//1.1绑定传递参数
jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, myJob);
//2.cron表达式调度构建器
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(myJob.getCronexpression());
cronScheduleBuilder = handleCronScheduleMisfirePolicy(myJob, cronScheduleBuilder);
//3.按照cronexpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger()
.withIdentity(getTriggerKey(myJob.getId(),
myJob.getJobGroup()))
.withSchedule(cronScheduleBuilder)
.build();
// 4.判断是否存在
if (scheduler.checkExists(getJobKey(myJob.getId(), myJob.getJobGroup()))) {
// 防止创建时存在数据问题 先移除,然后在执行创建操作
scheduler.deleteJob(getJobKey(myJob.getId(), myJob.getJobGroup()));
}
// 5.注册任务和定时器
scheduler.scheduleJob(jobDetail, trigger);
// 6.暂停任务
//判断定时任务状态 状态为1 暂停
if (myJob.getStatus().equals("1")) {
scheduler.pauseJob(getJobKey(myJob.getId(), myJob.getJobGroup()));
}
}
public static JobKey getJobKey(Long jobId, String jobGroup) {
return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
}
public static TriggerKey getTriggerKey(Long jobId, String jobGroup) {
return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
}
public static CronScheduleBuilder handleCronScheduleMisfirePolicy(MyJob myJob, CronScheduleBuilder cb)
throws Exception {
switch (myJob.getMisfirePolicy()) {
case ScheduleConstants.MISFIRE_DEFAULT:
return cb;
case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
return cb.withMisfireHandlingInstructionIgnoreMisfires();
case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
return cb.withMisfireHandlingInstructionFireAndProceed();
case ScheduleConstants.MISFIRE_DO_NOTHING:
return cb.withMisfireHandlingInstructionDoNothing();
default:
throw new Exception("参数有问题" + myJob.getMisfirePolicy());
}
}
}
3.2.6: JobService类
@Service
public class JobServiceImpl implements JobService {
@Autowired
private Scheduler scheduler;
@Autowired
private JobMapper jobMapper;
@PostConstruct
public void intJob() throws SchedulerException {
List myJobs = jobMapper.queryQuartz();
//先清理缓存
scheduler.clear();
//创建任务
myJobs.forEach(myJob -> {
try {
ScheduleUtil.intSchedule(scheduler,myJob);
} catch (SchedulerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
});
}
@Override
public void runJob(Long id) throws SchedulerException {
MyJob myJob = jobMapper.queryJobById(id);
JobDataMap dataMap = new JobDataMap();
//设置参数
dataMap.put(ScheduleConstants.TASK_PROPERTIES, myJob);
scheduler.triggerJob(ScheduleUtil.getJobKey(myJob.getId(), myJob.getJobGroup()), dataMap);
}
@Override
public void stopJob(Long id) throws SchedulerException {
MyJob myJob = jobMapper.queryJobById(id);
scheduler.pauseJob(ScheduleUtil.getJobKey(myJob.getId(), myJob.getJobGroup()));
}
@Override
public void resumeJob(Long id) throws SchedulerException {
MyJob myJob = jobMapper.queryJobById(id);
scheduler.resumeJob(ScheduleUtil.getJobKey(myJob.getId(), myJob.getJobGroup()));
}
@Override
public void deleteJob(Long id) throws SchedulerException {
//删除任务
MyJob myJob = jobMapper.queryJobById(id);
scheduler.deleteJob(ScheduleUtil.getJobKey(myJob.getId(), myJob.getJobGroup()));
//删除数据
MyJob myJob = scheduleMapper.deleteQuartzById(id);
//更新任务
List jobs = jobMapper.queryJob();
//先清理缓存
scheduler.clear();
jobs.forEach(j -> {
try {
ScheduleUtil.intSchedule(scheduler,j);
} catch (SchedulerException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
});
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateSchedulerJob(MyJob myJob) throws Exception {
//更新数据
scheduleMapper.updateQuartzById(myJob.getId());
// 判断是否存在
JobKey jobKey = ScheduleUtil.getJobKey(myJob.getId(), myJob.getJobGroup());
if (scheduler.checkExists(jobKey)){
// 防止创建时存在数据问题 先移除,然后在执行创建操作
scheduler.deleteJob(jobKey);
}
ScheduleUtil.intSchedule(scheduler,myJob);
}
}
4.使用方法
在数据库中增加两条如下数据
编写TaskService
//注意这里的bean名称
@Service("test")
public class TaskService {
//注意这里的方法名称 这俩个对应数据库中invoke_target字段
public void test(){
System.err.println("task测试成功");
}
public void testParam(String params){
System.out.println(params);
System.err.println("task测试成功");
}
}
任务会通过反射调用这里的方法,具体看原理如下分析
5.原理数据库字段的使用地方:
id、job_name、job_group、trigger_name、trigger_group、concurrent、cron_expression、misfire_policy这些字段在定时任务初始化时被当作生成jobkey和其他条件使用。
iid、job_name、nvoke_target这些字段在定时任务调度时被当作生成jobkey和调用自建方法的条件使用
初始化的每个任务都会根据数据库的数据生成自己的JobKey。(JobKey根据id和常量生成的)
getJobKey()是生成jobkey的方法
当用户在管理平台操作执行一次定时任务时,会拿着id传到后端,后端将任务数据查出来后,并使用数据生成对于的JobKey,执行对应jobkey的任务。
接下来定时任务会调用我们实现的Job接口中的execute方法
最后一步就是根据数据通过反射调用当时写好的方法
注意:上面方法处理的数据是数据库中的invoke_target字段,小数点前缀是Bean名称,后缀是方法名
通过以上的学习,进一步加强了对spring的认知,太强大了。



