Quartz之Job与JobDetail深入解析
发布时间 - 2026-01-11 01:53:33 点击率:次Quartz可以用来做什么?

Quartz是一个任务调度框架。比如你遇到这样的问题
想每月25号,信用卡自动还款
想每年4月1日自己给当年暗恋女神发一封匿名贺卡
想每隔1小时,备份一下自己的爱情动作片 学习笔记到云盘
这些问题总结起来就是:在某一个有规律的时间点干某件事。并且时间的触发的条件可以非常复杂(比如每月最后一个工作日的17:50),复杂到需要一个专门的框架来干这个事。 Quartz就是来干这样的事,你给它一个触发条件的定义,它负责到了时间点,触发相应的Job起来干活。
废话不多说,代码杠杠的。。。
public static void main(String[] args) {
try { //创建scheduler
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
//定义一个Trigger
Trigger trigger =TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") //定义name/group
.startNow()//一旦加入scheduler,立即生效
.withSchedule(SimpleScheduleBuilder.simpleSchedule() //使用SimpleTrigger
.withIntervalInSeconds(1) //每隔一秒执行一次
.repeatForever()) //一直执行
.build();
//定义一个JobDetail
JobDetail job =JobBuilder.newJob(HelloQuartz.class) //定义Job类为HelloQuartz类,这是真正的执行逻辑所在
.withIdentity("job1", "group1") //定义name/group
.usingJobData("name", "quartz") //定义属性
.build();
//加入这个调度
scheduler.scheduleJob(job, trigger);
//启动之
scheduler.start();
//运行一段时间后关闭
Thread.sleep(10000);
scheduler.shutdown(true);
} catch (Exception e) {
e.printStackTrace();
}
}
HelloQuartz类
public class HelloQuartz implements Job {
public void execute(JobExecutionContext context) throws JobExecutionException {
JobDetail detail = context.getJobDetail();
String name = detail.getJobDataMap().getString("name");
System.out.println("say hello to " + name + " at " + new Date());
}
}
jar包:
这个例子很好的覆盖了Quartz最重要的3个基本要素:
Scheduler:调度器。所有的调度都是由它控制。
Trigger: 定义触发的条件。例子中,它的类型是SimpleTrigger,每隔1秒中执行一次(什么是SimpleTrigger下面会有详述)。
JobDetail & Job: JobDetail 定义的是任务数据,而真正的执行逻辑是在Job中,例子中是HelloQuartz。 为什么设计成JobDetail + Job,不直接使用Job?这是因为任务是有可能并发执行,如果Scheduler直接使用Job,就会存在对同一个Job实例并发访问的问题。而JobDetail & Job 方式,sheduler每次执行,都会根据JobDetail创建一个新的Job实例,这样就可以规避并发访问的问题。
Scheduler
Scheduler就是Quartz的大脑,所有任务都是由它来设施。
Schduelr包含一个两个重要组件: JobStore和ThreadPool。
JobStore是会来存储运行时信息的,包括Trigger,Schduler,JobDetail,业务锁等。它有多种实现RAMJob(内存实现),JobStoreTX(JDBC,事务由Quartz管理),JobStoreCMT(JDBC,使用容器事务),ClusteredJobStore(集群实现)、TerracottaJobStore(什么是Terractta)。
ThreadPool就是线程池,Quartz有自己的线程池实现。所有任务的都会由线程池执行。
SchedulerFactory
SchdulerFactory,顾名思义就是来用创建Schduler了,有两个实现:DirectSchedulerFactory和 StdSchdulerFactory。前者可以用来在代码里定制你自己的Schduler参数。后者是直接读取classpath下的quartz.properties(不存在就都使用默认值)配置来实例化Schduler。通常来讲,我们使用StdSchdulerFactory也就足够了。
SchdulerFactory本身是支持创建RMI stub的,可以用来管理远程的Scheduler,功能与本地一样,可以远程提交个Job什么的。
1.job
实现类JobDetail
JobDetail job = JobBuilder.newJob(RemindJob.class)
.withIdentity("job1", "group1").build();//创建一个任务
/**
* 创建触发器
* 第一种方式 不太好
*/
SimpleTrigger trigger = TriggerBuilder.newTrigger().withIdentity("myTrigger", "myTriggerGroup").
withSchedule(SimpleScheduleBuilder.simpleSchedule().
withIntervalInSeconds(3).
repeatForever()).
startAt(new Date(System.currentTimeMillis()+1000)).build();
/**
* 创建触发器
* 第二种 方式 非常好
* 可以 好用 2013年每月的第三个星期五上午10:30触发 0 30 10 ? * 6#3 2013
* 2016年每月的第一个星期四下午16:17触发 0 17 16 ? * 5#1 2016
* 每天15点到16点每5分钟运行一次,此外,每天17点到18点每5分钟运行一次
*/
/*CronTrigger trigger=TriggerBuilder.newTrigger()
.withIdentity("myTrigger", "myTriggerGroup")
.withSchedule(CronScheduleBuilder.cronSchedule("0 18 16 ? * 5#1 2016")).build();*/
SchedulerFactory sf=new StdSchedulerFactory();//创建调度者工厂
Scheduler scheduler = sf.getScheduler();//创建一个调度者
scheduler.scheduleJob(job,trigger);//注册并进行调度
scheduler.start();//启动调度
//Thread.sleep(millis)
//scheduler.shutdown();//关闭调度
RemindJob 类的定义
*/
public class RemindJob implements Job {
private RemindService service=new RemindService();
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
service.printPlan("你好!");
Date date=new Date();
String time = date.toString();
System.out.println(time+"job is starting");
}
可以看到,我们传给scheduler一个JobDetail实例,因为我们在创建JobDetail时,将要执行的job的类名传给了JobDetail,所以scheduler就知道了要执行何种类型的job;每次当scheduler执行job时,在调用其execute(…)方法之前会创建该类的一个新的实例;执行完毕,对该实例的引用就被丢弃了,实例会被垃圾回收;这种执行策略带来的一个后果是,job必须有一个无参的构造函数(当使用默认的JobFactory时);另一个后果是,在job类中,不应该定义有状态的数据属性,因为在job的多次执行中,这些属性的值不会保留。
那么如何给job实例增加属性或配置呢?如何在job的多次执行中,跟踪job的状态呢?答案就是:JobDataMap,JobDetail对象的一部分。
JobDataMap
JobDataMap中可以包含不限量的(序列化的)数据对象,在job实例执行的时候,可以使用其中的数据;JobDataMap是Java Map接口的一个实现,额外增加了一些便于存取基本类型的数据的方法。
将job加入到scheduler之前,在构建JobDetail时,可以将数据放入JobDataMap,如下示例:
JobDetail job=JobBuilder.newJob(RemindJob.class)
.withIdentity("job1", "group1")
.usingJobData("hello", "we are family")
.build();
在job的执行过程中,可以从JobDataMap中取出数据,如下示例:
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
service.printPlan("你好!");
JobKey key=context.getJobDetail().getKey();
JobDataMap map = context.getJobDetail().getJobDataMap();
String string = map.getString("hello");
System.out.println(key+"==========="+string);
Date date=new Date();
String time = date.toString();
System.out.println(time+"job is starting");
}
如果你使用的是持久化的存储机制(本教程的JobStore部分会讲到),在决定JobDataMap中存放什么数据的时候需要小心,因为JobDataMap中存储的对象都会被序列化,因此很可能会导致类的版本不一致的问题;Java的标准类型都很安全,如果你已经有了一个类的序列化后的实例,某个时候,别人修改了该类的定义,此时你需要确保对类的修改没有破坏兼容性;更多细节,参考现实中的序列化问题。另外,你也可以配置JDBC-JobStore和JobDataMap,使得map中仅允许存储基本类型和String类型的数据,这样可以避免后续的序列化问题。
如果你在job类中,为JobDataMap中存储的数据的key增加set方法(如在上面示例中,增加setJobSays(String val)方法),那么Quartz的默认JobFactory实现在job被实例化的时候会自动调用这些set方法,这样你就不需要在execute()方法中显式地从map中取数据了。
在Job执行时,JobExecutionContext中的JobDataMap为我们提供了很多的便利。它是JobDetail中的JobDataMap和Trigger中的JobDataMap的并集,但是如果存在相同的数据,则后者会覆盖前者的值。
下面的示例,在job执行时,从JobExecutionContext中获取合并后的JobDataMap:
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
service.printPlan("你好!");
JobKey key=context.getJobDetail().getKey();
/* JobDataMap map = context.getJobDetail().getJobDataMap();
String string = map.getString("hello");
System.out.println(key+"==========="+string);*/
JobDataMap map = context.getMergedJobDataMap();
String string = map.getString("hello");
System.out.println(key+"--------------------- "+string);
以上这篇Quartz之Job与JobDetail深入解析就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。
# quartz
# job
# jobdetail
# 自己的
# 序列化
# 的是
# 每隔
# 如果你
# 创建一个
# 可以用来
# 是由
# 给大家
# 你好
# 点到
# 类中
# 是一个
# 这是
# 就会
# 是在
# 很好
# 会有
# 第一个
# 是有
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
如何用免费手机建站系统零基础打造专业网站?
网站建设整体流程解析,建站其实很容易!
制作网站软件推荐手机版,如何制作属于自己的手机网站app应用?
Laravel怎么设置路由分组Prefix_Laravel多级路由嵌套与命名空间隔离【步骤】
网页设计与网站制作内容,怎样注册网站?
如何在阿里云香港服务器快速搭建网站?
原生JS实现图片轮播切换效果
Laravel如何获取当前用户信息_Laravel Auth门面获取用户ID
成都品牌网站制作公司,成都营业执照年报网上怎么办理?
Laravel怎么实现支付功能_Laravel集成支付宝微信支付
如何选择可靠的免备案建站服务器?
Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践
如何基于PHP生成高效IDC网络公司建站源码?
如何快速使用云服务器搭建个人网站?
Laravel如何保护应用免受CSRF攻击?(原理和示例)
香港服务器网站卡顿?如何解决网络延迟与负载问题?
Python自然语言搜索引擎项目教程_倒排索引查询优化案例
如何在宝塔面板中创建新站点?
Windows Hello人脸识别突然无法使用
Laravel N+1查询问题如何解决_Eloquent预加载(Eager Loading)优化数据库查询
三星、SK海力士获美批准:可向中国出口芯片制造设备
Laravel如何处理文件下载请求?(Response示例)
Windows10电脑怎么查看硬盘通电时间_Win10使用工具检测磁盘健康
JavaScript如何实现倒计时_时间函数如何精确控制
如何解决hover在ie6中的兼容性问题
Android中Textview和图片同行显示(文字超出用省略号,图片自动靠右边)
Linux系统命令中screen命令详解
成都网站制作公司哪家好,四川省职工服务网是做什么用?
Laravel如何使用.env文件管理环境变量?(最佳实践)
深圳网站制作的公司有哪些,dido官方网站?
Laravel如何实现图片防盗链功能_Laravel中间件验证Referer来源请求【方案】
JS碰撞运动实现方法详解
如何在Windows服务器上快速搭建网站?
网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?
悟空浏览器如何设置小说背景色_悟空浏览器背景色设置【方法】
Win11怎么恢复误删照片_Win11数据恢复工具使用【推荐】
Laravel怎么集成Vue.js_Laravel Mix配置Vue开发环境
企业网站制作这些问题要关注
如何用AI帮你把自己的生活经历写成一个有趣的故事?
浏览器如何快速切换搜索引擎_在地址栏使用不同搜索引擎【搜索】
如何用wdcp快速搭建高效网站?
Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程
Laravel如何升级到最新版本?(升级指南和步骤)
Laravel如何监控和管理失败的队列任务_Laravel失败任务处理与监控
电视网站制作tvbox接口,云海电视怎样自定义添加电视源?
LinuxShell函数封装方法_脚本复用设计思路【教程】
Laravel数据库迁移怎么用_Laravel Migration管理数据库结构的正确姿势
三星网站视频制作教程下载,三星w23网页如何全屏?
简单实现Android验证码
网页制作模板网站推荐,网页设计海报之类的素材哪里好?

