传统Spring+Quartz实现的定时器一般都是通过配置文件中配置的,这就意味着如果我们修改了定时任务的时间,就得重新启动一下Tomcat,而且每次新建一个任务就得在spring中添加相关的配置信息,非常麻烦。基于上面的问题,这边给大家介绍一下Spring+Quartz如何实现动态定时器,如何避免创建多个定时任务的配置文件。
1.在开始之前,我们需求引入Quartz相关的依赖,pom.xml文件如下所示:
<!-- 定时任务 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.2.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.1</version>
</dependency>
2.我们需要在配置文件中配置定时任务的容器,也就是SchedulerFactoryBean,然后再配置一个定时任务管理器,这个类是我们自己定义的,而上面的SchedulerFactoryBean是来自依赖中的库。具体代码如下所示:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/data/mongo
http://www.springframework.org/schema/data/mongo/spring-mongo.xsd">
<!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序 -->
<bean id="startQuertz" lazy-init="true" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"></bean>
<!--这个类是用来设置触发时间的, startJobs方法启动调度容器,然后按照上面触发器每隔1s执行所配置的myJob2.doSomething()方法 -->
<bean id="quartzManager" class="com.infun.platform.quartz.QuartzManager" lazy-init="false" init-method="startJobs" >
<!--这个对象一定要注入,这样类才能进行管理,还有在类型要用get set方法,不然会报错。-->
<property name="scheduler" ref="startQuertz" />
</bean>
</beans>
这边我给这个配置文件取名为quartz.xml
3.第三步就是重中之重的,定时任务管理器的编写了,它负责去创建定时任务、修改任务触发事件、删除任务、停止定时任务容器等功能。下面我们具体看代码:
package com.infun.platform.quartz;
import org.quartz.*;
/**
* 定时任务配置管理中心
*
* @author linzhiqiang
* @date 2018/6/5
*/
public class QuartzManager {
private Scheduler scheduler;
/**
* @param jobName 任务名
* @param jobGroupName 任务组名
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param jobClass 任务
* @param cron 时间设置,参考quartz说明文档
* @param quartzTask task参数
* @Description: 添加一个定时任务
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public void addJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName, Class jobClass, String cron,TaskData quartzTask) {
try {
JobDataMap jobMap=new JobDataMap();
jobMap.put("task", quartzTask);
// 任务名,任务组,任务执行类
JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName)
.usingJobData(jobMap)
.build();
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
CronTrigger trigger = (CronTrigger) triggerBuilder.build();
// 调度容器设置JobDetail和Trigger
scheduler.scheduleJob(jobDetail, trigger);
// 启动
if (!scheduler.isShutdown()) {
scheduler.start();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param jobName
* @param jobGroupName
* @param triggerName 触发器名
* @param triggerGroupName 触发器组名
* @param cron 时间设置,参考quartz说明文档
* @Description: 修改一个任务的触发时间
*/
public void modifyJobTime(String jobName,
String jobGroupName, String triggerName, String triggerGroupName, String cron) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
if (trigger == null) {
return;
}
String oldTime = trigger.getCronExpression();
if (!oldTime.equalsIgnoreCase(cron)) {
/** 方式一 :调用 rescheduleJob 开始 */
// 触发器
TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
// 触发器名,触发器组
triggerBuilder.withIdentity(triggerName, triggerGroupName);
triggerBuilder.startNow();
// 触发器时间设定
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
// 创建Trigger对象
trigger = (CronTrigger) triggerBuilder.build();
// 方式一 :修改一个任务的触发时间
scheduler.rescheduleJob(triggerKey, trigger);
/** 方式一 :调用 rescheduleJob 结束 */
/** 方式二:先删除,然后在创建一个新的Job */
//JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
//Class<? extends Job> jobClass = jobDetail.getJobClass();
//removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
//addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
/** 方式二 :先删除,然后在创建一个新的Job */
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @param jobName
* @param jobGroupName
* @param triggerName
* @param triggerGroupName
* @Description: 移除一个任务
*/
public void removeJob(String jobName, String jobGroupName,
String triggerName, String triggerGroupName) {
try {
TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
scheduler.pauseTrigger(triggerKey);// 停止触发器
scheduler.unscheduleJob(triggerKey);// 移除触发器
scheduler.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:启动所有定时任务
*/
public void startJobs() {
try {
scheduler.start();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* @Description:关闭所有定时任务
*/
public void shutdownJobs() {
try {
if (!scheduler.isShutdown()) {
scheduler.shutdown();
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public Scheduler getScheduler() {
return scheduler;
}
public void setScheduler(Scheduler scheduler) {
this.scheduler = scheduler;
}
}
4.最后就是具体任务类的编写了,这边有几种方式:一种是你所有的定时任务都写再一个类里面,通过if去判断,二是你写多个任务类直接启动相关任务类就可以了,三是你就写一个任务类,但是不是通过if去判断,而是通过接口实现类去实现这个接口。关于三种方式,我推荐第三种,因为第三者可扩展性最高。下面我们具体看一下任务类的实现:
package com.infun.platform.quartz;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
/**
*
* 小队定时任务
* @author linzhiqiang
* @date 2018/6/4
*/
public class QuartzTask implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
//执行任务
JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();
TaskData quartzTask = (TaskData)dataMap.get("task");
// 调用接口函数
quartzTask.execute();
}
}
任务的参数接口代码:
package com.infun.platform.quartz;
/**
* 任务接口,接口具体实现由调用者来实现
* @author linzhiqiang
* @date 2018/6/5
*/
public interface TaskData {
/**
* 任务具体的执行方法
*/
public void execute();
}
任务的参数接口实现类代码:
package com.infun.platform.quartz;
/**
*
* @author linzhiqiang
* @date 2018/6/5
*/
public class TaskDataImpl implements TaskData {
@Override
public void execute() {
System.out.println("定时任务。。。。。。。。。。。。执行中。。。。。");
}
}
最后我们写一个测试类来测试一下,定时任务有没有生效,测试类如下所示:
package com.infun.platform.quartz;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*
* @author linzhiqiang
* @date 2018/6/5
*/
public class Test {
public static void main(String[] args) throws BeansException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("quartz.xml");
QuartzManager quartzManager = (QuartzManager) ctx.getBean("quartzManager");
try {
System.out.println("【系统启动】开始(每1秒输出一次 job2)...");
Thread.sleep(5000);
System.out.println("【增加job1启动】开始(每1秒输出一次)...");
quartzManager.addJob("test", "test", "test", "test", QuartzTask.class, "0/1 * * * * ?",new TaskDataImpl());
Thread.sleep(5000);
System.out.println("【修改job1时间】开始(每2秒输出一次)...");
quartzManager.modifyJobTime("test", "test", "test", "test", "0/2 * * * * ?");
//
Thread.sleep(10000);
System.out.println("【移除job1定时】开始...");
quartzManager.removeJob("test", "test", "test", "test");
// 关掉任务调度容器
quartzManager.shutdownJobs();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果如下所示:
结果显示定时任务成功启动,并且正确执行。这里我们可以修改一下测试类,将我们需要的定时任务做成API暴露给其它模块来调用,API类如下所示:
package com.infun.platform.quartz;
/**
*
* 任务调度服务
* @author linzhiqiang
* @date 2018/6/5
*/
public class QuartzService {
public void setQuartzManager(QuartzManager quartzManager) {
this.quartzManager = quartzManager;
}
private QuartzManager quartzManager;
/**
* 启动定时任务
* @param jobClass 任务的task类
* @param cron 定时任务的表达式
*/
public void startTask(Class jobClass, String cron,TaskData quartzTask){
String jobName = jobClass.getName();
quartzManager.addJob(jobName, jobName, jobName, jobName, jobClass, cron, quartzTask);
}
/**
* 修改定时任务时间
* @param jobName 任务的task名称
* @param cron 定时任务的表达式
*/
public void updateTaskTime(String jobName, String cron){
quartzManager.modifyJobTime(jobName,jobName,jobName,jobName, cron);
}
/**
* 移除定时任务
* @param jobName 任务的task名称
* @param cron 定时任务的表达式
*/
public void removeTask(String jobName, String cron){
quartzManager.removeJob(jobName,jobName,jobName,jobName);
}
/**
* 关闭定时任务容器
* 慎用
*/
public void shutdownJobs(){
// 关掉任务调度容器
quartzManager.shutdownJobs();
}
}

Spring整合Quartz实现动态定时器就全部结束了,我们可以将配置文件加入到web.xml中去,这样我们项目一启动就可以马上执行定时任务了。

想要更多干货、技术猛料的孩子,快点拿起手机扫码关注我,我在这里等你哦~

Spring整合Quartz实现动态定时器相关推荐

  1. java 动态添加定时器_Spring整合Quartz实现动态定时器的示例代码

    一.版本说明 spring3.1以下的版本必须使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然会出错. 原因:spring对于quartz的支持实现,org.springf ...

  2. java 定时任务插件_详解Spring整合Quartz实现动态定时任务

    最近项目中需要用到定时任务的功能,虽然spring 也自带了一个轻量级的定时任务实现,但感觉不够灵活,功能也不够强大.在考虑之后,决定整合更为专业的Quartz来实现定时任务功能. 普通定时任务 首先 ...

  3. spring整合quartz框架

    前言: 在一些项目中,往往需要定时的去执行一些任务,比如商城项目,每天0点去统计前一天的销量.那么如何实现呢,总不可能我们每天0点手动的去执行统计销量的方法吧,这时就quartz就起作用了. quar ...

  4. 使用Spring整合Quartz轻松完成定时任务

    一.背景 上次我们介绍了如何使用Spring Task进行完成定时任务的编写,这次我们使用Spring整合Quartz的方式来再一次实现定时任务的开发,以下奉上开发步骤及注意事项等. 二.开发环境及必 ...

  5. Spring 整合 Quartz 分布式调度

    转载自 Spring 整合 Quartz 分布式调度 本文旨在对 Spring+Quartz 分布式调度有一个直观的了解,通过实际的使用来解决问题. 前言 为了保证应用的高可用和高并发性,一般都会部署 ...

  6. Spring整合Quartz集群部署

    Spring整合Quartz集群部署 Quartz的分布式模式 数据表创建 quartz.properties spring-job.xml Quartz的分布式模式 集群中的每个节点都是一个独立的Q ...

  7. Spring整合Quartz实现持久化、动态设定时间

    一.spring整合 网上一搜有很多整合的方式,这里我采用了其中的一种(暂时还没有对其他的方法研究过). 对于spring的整合其中的任务,spring提供了几个类.接口(这些类都实现了Job接口): ...

  8. 使用spring整合quartz进行定时器调用(图文案例)

    现实中用到定时器的功能太多了,比如闹钟,设置定时音乐... 本人毕设中考勤功能也需要用到定时器(下面链接可查看): https://blog.csdn.net/C_bianchengxiaobai/a ...

  9. Spring整合Quartz实现定时任务

    Quartz框架是一个极其成功的开源任务调度框架,目前很多公司在实现任务调度上都直接使用或在借鉴的基础上实现了自己的任务调度框架,Quartz使用Trigger,Job和JobDetail对象实现调度 ...

  10. Spring 整合Mybatis Mapper动态代理方法

    先看项目目录结构 很清爽了 最重要的Spring的核心配置文件,看一下 <?xml version="1.0" encoding="UTF-8"?> ...

最新文章

  1. keras 的 example 文件 cifar10_resnet.py 解析
  2. Linux下修改PATH环境变量
  3. php 正则 最后一个字符,关于正则表达式:在PHP中查找字符串中的最后一个字符...
  4. spring 数组中随机取几个_游戏编程中需要掌握哪些数学物理知识
  5. Python异常处理体系简介(1)
  6. Android版哆啦A梦连连看游戏源码完整版
  7. ora22813操作数值超出系统的限制_最新:华为“鸿蒙”操作系统终于面世!一旦遭到限制,将随时启用...
  8. Redis数据结构之集合
  9. 超5000元!骁龙660新机发布:限量供应价格感人
  10. 基于消息的异步套接字
  11. 小白必须要会的Github操作 确定不进来看看?
  12. 第 45 届国际大学生程序设计竞赛(ICPC)亚洲区域赛(昆明),签到题HIL
  13. POJ-1426-Find The Multiple
  14. 纵坐标是横的还是竖的_600*1200墙砖横贴好,还是竖贴好?讲讲这两种贴法的问题...
  15. php中合并数组保留键值,如何使用php合并数组并保留键值的方法
  16. 百度地图+城市联动实现实时触发查询地址
  17. Ubuntu环境下远程调试Android手机设备
  18. 【Python量化】蒙特卡洛模拟法预测股价走势
  19. Django开发个人博客网站——11、通过regroup实现博客的归档
  20. IDEA谷歌翻译插件提示:更新 TKK 失败,请检查网络连接

热门文章

  1. Linux防火墙配置工具iptables中MASQUERADE的含义
  2. 看透说破:客户服务首解率(FCR)的迷思
  3. 世预赛乌拉圭VS哥伦比亚最新赛事解析:客场保平属性强怎么下单
  4. Landsat系列卫星数据应用介绍
  5. Windows7 内部版本7601 此Windows副本不是正版
  6. 如何检索教授的国家自然科学基金的完整版结题报告
  7. 申请微信公众账号测试号
  8. 贪心算法解决雷达站建站问题
  9. C++实践之华氏温度转摄氏温度
  10. Unable to find a single main class from the following candidates 问题解决