源码:http://chuhanzhi.com/?p=45 点击最下方链接即可下载
在实际项目应用中经常会用到定时任务,可以通过quartz和spring的简单配置即可完成,但如果要改变任务的执行时间、频率,废弃任务等就需要改变配置甚至代码需要重启服务器,这里介绍一下如何通过quartz与spring的组合实现动态的改变定时任务的状态的一个实现。
参考文章:http://www.meiriyouke.net/?p=82
本文章适合对quartz和spring有一定了解的读者。
spring版本为3.2 quartz版本为2.2.1 如果使用了quartz2.2.1 则spring版本需3.1以上
1.
spring中引入注册bean
<bean id="schedulerFactoryBean" class="org.springframework.scheduling.quartz.SchedulerFactoryBean" />
为什么要与spring结合?
与spring结合可以使用spring统一管理quartz中任务的生命周期,使得web容器关闭时所有的任务一同关闭。如果不用spring管理可能会出现web容器关闭而任务仍在继续运行的情况,不与spring结合的话要自己控制任务在容器关闭时一起关闭。
2.创建保存计划任务信息的实体类
/** * * @Description: 计划任务信息 * @author snailxr * @date 2014年4月24日 下午10:49:43 */ public class ScheduleJob { public static final String STATUS_RUNNING = "1"; public static final String STATUS_NOT_RUNNING = "0"; public static final String CONCURRENT_IS = "1"; public static final String CONCURRENT_NOT = "0"; private Long jobId; private Date createTime; private Date updateTime; /** * 任务名称 */ private String jobName; /** * 任务分组 */ private String jobGroup; /** * 任务状态 是否启动任务 */ private String jobStatus; /** * cron表达式 */ private String cronExpression; /** * 描述 */ private String description; /** * 任务执行时调用哪个类的方法 包名+类名 */ private String beanClass; /** * 任务是否有状态 */ private String isConcurrent; /** * spring bean */ private String springId; /** * 任务调用的方法名 */ private String methodName; //get set....... }
该实体类与数据库中的表对应,在数据库中存储多个计划任务。
注意:jobName 跟 groupName的组合应该是唯一的,beanClass springId至少有一个
在项目启动时运行以下代码:
public void init() throws Exception { Scheduler scheduler = schedulerFactoryBean.getScheduler(); // 这里从数据库中获取任务信息数据 List<ScheduleJob> jobList = scheduleJobMapper.getAll(); for (ScheduleJob job : jobList) { addJob(job); } }
/** * 添加任务 * * @param scheduleJob * @throws SchedulerException */ public void addJob(ScheduleJob job) throws SchedulerException { if (job == null || !ScheduleJob.STATUS_RUNNING.equals(job.getJobStatus())) { return; } Scheduler scheduler = schedulerFactoryBean.getScheduler(); log.debug(scheduler + ".......................................................................................add"); TriggerKey triggerKey = TriggerKey.triggerKey(job.getJobName(), job.getJobGroup()); CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); // 不存在,创建一个 if (null == trigger) { Class clazz = ScheduleJob.CONCURRENT_IS.equals(job.getIsConcurrent()) ? QuartzJobFactory.class : QuartzJobFactoryDisallowConcurrentExecution.class; JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity(job.getJobName(), job.getJobGroup()).build(); jobDetail.getJobDataMap().put("scheduleJob", job); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression()); trigger = TriggerBuilder.newTrigger().withIdentity(job.getJobName(), job.getJobGroup()).withSchedule(scheduleBuilder).build(); scheduler.scheduleJob(jobDetail, trigger); } else { // Trigger已存在,那么更新相应的定时设置 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression()); // 按新的cronExpression表达式重新构建trigger trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); // 按新的trigger重新设置job执行 scheduler.rescheduleJob(triggerKey, trigger); } }
看到代码第20行根据scheduleJob类中CONCURRENT_IS来判断任务是否有状态。来给出不同的Job实现类
/** * * @Description: 若一个方法一次执行不完下次轮转时则等待改方法执行完后才执行下一次操作 * @author snailxr * @date 2014年4月24日 下午5:05:47 */ @DisallowConcurrentExecution public class QuartzJobFactoryDisallowConcurrentExecution implements Job { public final Logger log = Logger.getLogger(this.getClass()); @Override public void execute(JobExecutionContext context) throws JobExecutionException { ScheduleJob scheduleJob = (ScheduleJob) context.getMergedJobDataMap().get("scheduleJob"); TaskUtils.invokMethod(scheduleJob); } }
/** * * @Description: 计划任务执行处 无状态 * @author snailxr * @date 2014年4月24日 下午5:05:47 */ public class QuartzJobFactory implements Job { public final Logger log = Logger.getLogger(this.getClass()); @Override public void execute(JobExecutionContext context) throws JobExecutionException { ScheduleJob scheduleJob = (ScheduleJob) context.getMergedJobDataMap().get("scheduleJob"); TaskUtils.invokMethod(scheduleJob); } }
真正执行计划任务的代码就在TaskUtils.invokMethod(scheduleJob)里面
通过scheduleJob的beanClass或springId通过反射或spring来获得需要执行的类,通过methodName来确定执行哪个方法
public class TaskUtils { public final static Logger log = Logger.getLogger(TaskUtils.class); /** * 通过反射调用scheduleJob中定义的方法 * * @param scheduleJob */ public static void invokMethod(ScheduleJob scheduleJob) { Object object = null; Class clazz = null; //springId不为空先按springId查找bean if (StringUtils.isNotBlank(scheduleJob.getSpringId())) { object = SpringUtils.getBean(scheduleJob.getSpringId()); } else if (StringUtils.isNotBlank(scheduleJob.getBeanClass())) { try { clazz = Class.forName(scheduleJob.getBeanClass()); object = clazz.newInstance(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } if (object == null) { log.error("任务名称 = [" + scheduleJob.getJobName() + "]---------------未启动成功,请检查是否配置正确!!!"); return; } clazz = object.getClass(); Method method = null; try { method = clazz.getDeclaredMethod(scheduleJob.getMethodName()); } catch (NoSuchMethodException e) { log.error("任务名称 = [" + scheduleJob.getJobName() + "]---------------未启动成功,方法名设置错误!!!"); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } if (method != null) { try { method.invoke(object); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
对任务的暂停,删除,修改等操作
** * 获取所有计划中的任务列表 * * @return * @throws SchedulerException */ public List<ScheduleJob> getAllJob() throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup(); Set<JobKey> jobKeys = scheduler.getJobKeys(matcher); List<ScheduleJob> jobList = new ArrayList<ScheduleJob>(); for (JobKey jobKey : jobKeys) { List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey); for (Trigger trigger : triggers) { ScheduleJob job = new ScheduleJob(); job.setJobName(jobKey.getName()); job.setJobGroup(jobKey.getGroup()); job.setDescription("触发器:" + trigger.getKey()); Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey()); job.setJobStatus(triggerState.name()); if (trigger instanceof CronTrigger) { CronTrigger cronTrigger = (CronTrigger) trigger; String cronExpression = cronTrigger.getCronExpression(); job.setCronExpression(cronExpression); } jobList.add(job); } } return jobList; } /** * 所有正在运行的job * * @return * @throws SchedulerException */ public List<ScheduleJob> getRunningJob() throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs(); List<ScheduleJob> jobList = new ArrayList<ScheduleJob>(executingJobs.size()); for (JobExecutionContext executingJob : executingJobs) { ScheduleJob job = new ScheduleJob(); JobDetail jobDetail = executingJob.getJobDetail(); JobKey jobKey = jobDetail.getKey(); Trigger trigger = executingJob.getTrigger(); job.setJobName(jobKey.getName()); job.setJobGroup(jobKey.getGroup()); job.setDescription("触发器:" + trigger.getKey()); Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey()); job.setJobStatus(triggerState.name()); if (trigger instanceof CronTrigger) { CronTrigger cronTrigger = (CronTrigger) trigger; String cronExpression = cronTrigger.getCronExpression(); job.setCronExpression(cronExpression); } jobList.add(job); } return jobList; } /** * 暂停一个job * * @param scheduleJob * @throws SchedulerException */ public void pauseJob(ScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup()); scheduler.pauseJob(jobKey); } /** * 恢复一个job * * @param scheduleJob * @throws SchedulerException */ public void resumeJob(ScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup()); scheduler.resumeJob(jobKey); } /** * 删除一个job * * @param scheduleJob * @throws SchedulerException */ public void deleteJob(ScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup()); scheduler.deleteJob(jobKey); } /** * 立即执行job * * @param scheduleJob * @throws SchedulerException */ public void runAJobNow(ScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); JobKey jobKey = JobKey.jobKey(scheduleJob.getJobName(), scheduleJob.getJobGroup()); scheduler.triggerJob(jobKey); } /** * 更新job时间表达式 * * @param scheduleJob * @throws SchedulerException */ public void updateJobCron(ScheduleJob scheduleJob) throws SchedulerException { Scheduler scheduler = schedulerFactoryBean.getScheduler(); TriggerKey triggerKey = TriggerKey.triggerKey(scheduleJob.getJobName(), scheduleJob.getJobGroup()); CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()); trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); scheduler.rescheduleJob(triggerKey, trigger); }
小提示
更新表达式,判断表达式是否正确可用一下代码
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("xxxxx");
抛出异常则表达式不正确
相关推荐
可以通过quartz和spring的简单配置即可完成,但如果要改变任务的执行时间、频率,废弃任务等就需要改变配置甚至代码需要重启服务器,这里介绍一下如何通过quartz与spring的组合实现动态的改变定时任务的状态的一个...
当结合Quartz,一个强大的任务调度库,我们可以实现动态的定时任务创建,这在业务逻辑中有着广泛的应用,如数据同步、定时报表生成等。 **Spring框架** Spring框架是Java开发者必备的工具之一。它提供了一个统一的...
在IT行业中,构建高效、可扩展的Web应用是至关重要的,而"spring+springMVC+mybatis+quartz动态定时任务创建"就是一个常见的技术栈,用于实现这样的目标。这个组合充分利用了各组件的优势,提供了强大的后端服务支持...
在这个“quartz_springbatch_dynamic”项目中,我们将看到如何将这两个强大的工具结合起来,以实现动态集群环境中的定时任务执行,并使用MySQL作为数据存储。 Quartz是一个开源的作业调度框架,允许开发者创建、...
本篇文章将详细探讨如何在SpringBoot项目中整合Quartz,实现动态配置定时任务。 首先,我们需要在SpringBoot项目中引入Quartz的相关依赖。在`pom.xml`文件中添加以下Maven依赖: ```xml <groupId>org.spring...
本项目旨在演示如何利用Spring和Quartz从数据库中动态加载定时任务,并实现对它们的增删改查功能。以下是关于这个主题的详细知识讲解。 首先,Quartz是一个开源的作业调度框架,它允许开发者创建、安排和执行定时...
基于Spring的Quartz动态定时任务增删改查,代码简洁。后端采用SpringMvc+Spring+Mybatis+Quartz,前端采用Bootstrap框架,数据库采用MySQL;完成定时任务动态任务初始化,增删改查
Spring和Quartz是两个强大的工具,可以协同工作来实现动态管理的定时任务。本文将深入探讨如何利用Spring框架和Quartz库创建和管理这些任务。 **Spring框架** 是一个广泛应用的Java企业级开发框架,它提供了丰富的...
Spring与Quartz的结合使用,使得我们可以方便地在Spring框架下管理定时任务,同时还能实现任务的动态添加、修改和删除。 Quartz是一个开源的作业调度框架,支持丰富的调度策略,包括简单的定时执行、按日程表执行...
本篇文章将详细探讨如何在Spring Boot项目中整合Quartz,并通过MySQL数据库实现定时任务的动态配置。 首先,我们需要在项目中添加依赖。在Spring Boot的`pom.xml`文件中,引入Spring Boot的`spring-boot-starter-...
本项目“Springboot2-Quartz 后台可动态配置的定时任务”是基于SpringBoot 2.x版本与Quartz Scheduler整合的一个示例,它展示了如何在后台管理系统中动态地创建、更新和删除定时任务,以及监控这些任务的状态,为...
Spring + quartz 定时任务修改定时时间不重启服务
该项目是一套基于Spring框架和Quartz调度器的Java动态定时任务解决方案源码,包含24个文件,涵盖12个Java源文件、2个XML配置文件、1个Git忽略文件、1个LICENSE文件、1个Markdown文件、1个SQL文件、1个DDL文件、1个...
Spring Quartz 动态暂停、恢复、修改定时任务的一个demo,使用maven构建,框架采用spring springmvc jpa,数据库mysql,含数据库脚本,运行可用,页面访问地址http://localhost:8080/quartz_demo/quartz/list
2.通过Spring是JAR-quartz写的一个定时任务 1)普通的定时任务,定时完成指定的任务 2)通过前台动态分配定时任务 可指定多个任务,可同时执行任务,可以精确到时分秒扫描并执行任务 3)可以完成稍微复杂点的任务 ...
Quartz和Spring结合实现动态定时任务是企业级应用中常见的一种技术组合,它允许开发者灵活地定义、管理和执行定时任务。Quartz是一个开源的作业调度框架,而Spring框架则为Java应用程序提供了强大的依赖注入(DI)和...
Spring框架作为Java领域广泛使用的轻量级框架,提供了与第三方库Quartz的整合,使得开发者能够轻松地在Spring应用中实现复杂的定时任务调度。Quartz是一款开源的作业调度框架,支持丰富的调度策略,可以满足各种定时...
在这两种方式中,Spring框架提供了自己的定时任务工具Spring Task,以及与专业定时任务框架Quartz集成的能力。 首先,对于Java自带的定时任务实现,我们可以使用java.util.Timer和java.util.TimerTask类。Timer类...
本项目旨在实现对Quartz定时任务的动态管理,包括添加、停止和恢复等操作。前端采用jQuery和Bootstrap构建,提供用户友好的可视化界面,同时应用了MyBatis分页插件来优化数据查询性能。 首先,让我们详细了解一下...
在多应用服务器负载均衡环境下,Spring Quartz定时任务的重复执行问题是一个常见的挑战。Spring Quartz是一个强大的、开源的作业调度框架,允许开发者定义和执行复杂的定时任务。然而,当多个服务器实例并行运行时,...