在日常开发汇总,经常会遇到需要定时任务的场景,简单的,可以使用Spring的定时任务调度框架,也可以使用Quartz。无论使用哪种,都需要解决一个问题,那就是集群问题。一般情况下,定时任务能且仅能运行于一台应用实例上。

前提

本文工程基于spring boot 2.1.7.RELEASE

工程配置

 一、pom依赖

如下图所示:

二、yml配置

yml配置如下图所示:

三、quartz.properties

quartz相关属性配置如图:

注意:

1、重中之重,要设置org.quartz.jobStore.isClustered=true,开启集群模式

2、其它配置见释义

四、调度器配置

使用SchedulerFactoryBeanCustomizer个性化调度器

@Configuration
public class SysConfig { private final DataSource dataSource; public SysConfig(DataSource dataSource) {
this.dataSource = dataSource;
} @Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer() {
return (schedulerFactoryBean) -> {
schedulerFactoryBean.setDataSource(dataSource);
schedulerFactoryBean.setConfigLocation(new ClassPathResource("quartz.properties"));
};
} }

五、系统启动

系统启动,如显示quartz以cluster模式启动,则证明配置成功。如图所示:

编写任务

一、Job

代码如下:

package com.luas.quartz.cluster.demo.quartz.job;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.quartz.QuartzJobBean; public class UserJob extends QuartzJobBean { @Value("${server.port}")
private String port; private String name; private Integer age; @Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println(String.format("the user job is execute on port %s. it's name is %s, age is %s", port, name, age));
} public String getPort() {
return port;
} public void setPort(String port) {
this.port = port;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Integer getAge() {
return age;
} public void setAge(Integer age) {
this.age = age;
}
}

二、Controller触发

代码如下:

package com.luas.quartz.cluster.demo.controller;

import com.luas.quartz.cluster.demo.quartz.job.UserJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController; import java.time.LocalDateTime; @RestController
@RequestMapping("/job")
public class JobController { @Autowired
private Scheduler scheduler; @RequestMapping("/user")
public Object user() throws Exception {
JobBuilder jobBuilder = JobBuilder
.newJob(UserJob.class)
.withIdentity(new JobKey("UserJob", "default"))
.withDescription("a demo quartz job")
.storeDurably(); JobDataMap jobDataMap = new JobDataMap();
jobDataMap.put("name", "luas");
jobDataMap.put("age", 18); TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger()
.withIdentity(new TriggerKey("UserJob's trigger 1", "default"))
.withSchedule(createSimpleScheduleBuilder())
.forJob(new JobKey("UserJob", "default"))
.usingJobData(jobDataMap)
.startNow(); this.scheduler.scheduleJob(jobBuilder.build(), triggerBuilder.build()); return LocalDateTime.now();
} private ScheduleBuilder createSimpleScheduleBuilder() {
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInMilliseconds(10000)
.withRepeatCount(100); return simpleScheduleBuilder;
} }

三、系统启动

依次启动8080、8082两个实例。idea默认只能启动一个实例,需要配置并行运行才可以运行两个相同的实例,如下图所示,勾选Allow parallel run即可。

访问:http://localhost:8080/quartz/job/user,页面返回当前时间。

此时,8080和8082控制台信息分别如图所示:

8080:

8082:

可以看出,Quartz运行在8080实例上,而8082实例处于监控状态。

四、切换运行实例

停止8080实例,手工模拟服务器故障,观察8082实例控制台输出,发现quartz已经运行在8082实例上,如图所示:

8080停止:

8082接管:

问题

1、启动报错:Couldn't store job: JobDataMap values must be Strings when the 'useProperties' property is set.

修改quartz.properties配置中org.quartz.jobStore.useProperties=false

2、UserJob中@Value注解标注的port属性如何会自动注入、name、age属性如何会自动注入?

参考QuartzAutoConfiguration、SpringBeanJobFactory类的如下片段:

3、数据结构

Quartz官网下载分发包,下载地址。下载完成后,在压缩包路径docs\dbTables下,有各个数据库相对应的脚本文件,选择自己对应的脚本执行即可。如本文选择的为tables_mysql_innodb.sql。

其它

一、源码

本文源码地址如下:

  • github:https://github.com/liuminglei/learning-demo/tree/master/quartz-cluster-demo

  • gitee:https://gitee.com/xbd521/learning-demo/tree/master/quartz-cluster-demo

二、集成框架

基于quartz的集群式、非集群式轻量封装定时任务调度框架-quartz、quartz-boot已共享,配置、操作更便捷、高效,欢迎star、fork。

quartz-boot:

  • github:https://github.com/liuminglei/quartz-boot

  • gitee:https://gitee.com/xbd521/quartz-boot

quartz

  • github:https://github.com/liuminglei/quartz

  • gitee:https://gitee.com/xbd521/quartz

本文由【银河架构师】原创,转载请注明作者及出处。另附本文地址:

https://www.cnblogs.com/luas/p/12040304.html

微信搜索【银河架构师】,发现更多精彩内容。

技术资料领取方法:关注公众号,回复微服务,领取微服务相关电子书;回复MK精讲,领取MK精讲系列电子书;回复JAVA 进阶,领取JAVA进阶知识相关电子书;回复JAVA面试,领取JAVA面试相关电子书,回复JAVA WEB领取JAVA WEB相关电子书。

 

 

最新文章

  1. 关于Android中res目录strings.xml文件中的转义字符之笔录
  2. JavaWeb中读取文件资源的路径问题
  3. 关于android 5.0对开发带来的影响
  4. 夺命雷公狗ThinkPHP项目之----企业网站27之网站前台单页的完成(从百度编辑器里面取出文章数据)
  5. jquery放大镜插件与样式
  6. Fork 一个仓库并同步
  7. php 封装Mysql数据库操作类
  8. 玩转Node.js单元测试
  9. 远程调用服务框架-CXF(WebServic)
  10. python学习笔记-问题
  11. C# DataGridView绑定List对象时,利用BindingList来实现增删查改
  12. SpringBoot启动原理及相关流程
  13. html实体命名
  14. 微信录音文件上传到服务器以及amr转化成MP3格式,linux上转换简单方法
  15. OpenCV学习(一)基础篇
  16. Vue + Element UI 实现权限管理系统 前端篇(十):动态加载菜单
  17. weblogic在64位windows的设置
  18. 基于jQuery仿QQ音乐播放器网页版代码
  19. 移动IP 它最初设想每个人都在编写应用层(7)API而不是传输层(4)API 对于QUIC,连接的标识符不是“套接字”(源/目标端口/地址协议组合)的传统概念,而是分配给连接的64位标识符
  20. URAL 2072 Kirill the Gardener 3

热门文章

  1. 从cocos2dx源代码看android和iOS跨平台那些事
  2. easyui+ef实现省市区三级联动
  3. 使用navicat操作PostPreSql创建表并设置主键自增和触发器
  4. 装饰者模式学习:模拟咖啡馆的点单系统来剖析装饰者模式的使用 + 装饰者模式在java I/O 中的应用
  5. alpha week 2/2 Scrum立会报告+燃尽图 01
  6. C/C++ 条件编译静态库
  7. Hadoop之HDFS文件系统(二)
  8. JavaScript笔记四
  9. 1像素border的实现(vue.js)
  10. Java架构师必知:什么是单点登录,主要会应用于哪些场景?