Spring Boot Quartz

主要内容

  • Spring Scheduler 框架
  • Quartz 框架,功能强大,配置灵活
  • Quartz 集群
  • mysql 持久化定时任务脚本(tables_mysql.sql)

介绍

在工程中时常会遇到一些需求,例如定时刷新一下配置、隔一段时间检查下网络状态并发送邮件等诸如此类的定时任务。

定时任务本质就是一个异步的线程,线程可以查询或修改并执行一系列的操作。由于本质是线程,在 Java 中可以自行编写一个线程池对定时任务进行控制,但这样效率太低了,且功能有限,属于重复造轮子。

分布式任务调度应用场景

Quartz的集群功能通过故障转移和负载平衡功能为您的调度程序带来高可用性和可扩展性。

调度程序中会有很多定时任务需要执行,一台服务器已经不能满足使用,需要解决定时任务单机单点故障问题。

用Quartz框架,在集群环境下,通过数据库锁机制来实现定时任务的执行;独立的 Quartz 节点并不与另一其的节点或是管理节点通信。

Spring Scheduler 实现定时任务

1.定义 Task 类

  1. /**
  2. * Spring Scheduled示例
  3. */
  4. @Component
  5. public class ScheduledTask {
  6. private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
  7. private Integer count0 = 1;
  8. private Integer count1 = 1;
  9. private Integer count2 = 1;
  10. @Scheduled(fixedRate = 5000)
  11. public void reportCurrentTime() throws InterruptedException {
  12. System.out.println(String.format("reportCurrentTime第%s次执行,当前时间为:%s", count0++, dateFormat.format(new Date())));
  13. }
  14. @Scheduled(fixedDelay = 5000)
  15. public void reportCurrentTimeAfterSleep() throws InterruptedException {
  16. System.out.println(String.format("reportCurrentTimeAfterSleep第%s次执行,当前时间为:%s", count1++, dateFormat.format(new Date())));
  17. }
  18. @Scheduled(cron = "0 0 1 * * *")
  19. public void reportCurrentTimeCron() throws InterruptedException {
  20. System.out.println(String.format("reportCurrentTimeCron第%s次执行,当前时间为:%s", count2++, dateFormat.format(new Date())));
  21. }
  22. }

2.启动定时任务

在Spring Boot的主类中加入@EnableScheduling注解,启用定时任务的配置

  1. @RunWith(SpringRunner.class)
  2. @SpringBootTest
  3. @Slf4j
  4. @EnableScheduling
  5. public class ScheduledTaskTests {
  6. @Test
  7. public void test() {
  8. log.info("启动了ScheduledTask定时作业");
  9. while (true) {
  10. }
  11. }
  12. }

quartz实现分布式定时任务

  1. quartz 是一个开源的分布式调度库,它基于java实现。
  2. > 它有着强大的调度功能,支持丰富多样的调度方式,比如简单调度,基于cron表达式的调度等等。
  3. > 支持调度任务的多种持久化方式。比如支持内存存储,数据库存储,Terracotta server 存储。
  4. > 支持分布式和集群能力。
  5. > 采用JDBCJobStore方式存储时,针对事务的处理方式支持全局事务(和业务服务共享同一个事务)和局部事务(quarzt 单独管理自己的事务)
  6. > 基于plugin机制以及listener机制支持灵活的扩展。

1.pom.xml配置

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-quartz</artifactId>
  4. </dependency>
  5. <!-- mysql -->
  6. <dependency>
  7. <groupId>mysql</groupId>
  8. <artifactId>mysql-connector-java</artifactId>
  9. </dependency>
  10. <!-- orm -->
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-data-jpa</artifactId>
  14. </dependency>

2.spring-quartz.properties集群配置

  1. #============================================================================
  2. # 配置JobStore
  3. #============================================================================
  4. # JobDataMaps是否都为String类型,默认false
  5. org.quartz.jobStore.useProperties=false
  6. # 表的前缀,默认QRTZ_
  7. org.quartz.jobStore.tablePrefix = QRTZ_
  8. # 是否加入集群
  9. org.quartz.jobStore.isClustered = true
  10. # 调度实例失效的检查时间间隔 ms
  11. org.quartz.jobStore.clusterCheckinInterval = 5000
  12. # 当设置为“true”时,此属性告诉Quartz 在非托管JDBC连接上调用setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED)。
  13. org.quartz.jobStore.txIsolationLevelReadCommitted = true
  14. # 数据保存方式为数据库持久化
  15. org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
  16. # 数据库代理类,一般org.quartz.impl.jdbcjobstore.StdJDBCDelegate可以满足大部分数据库
  17. org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
  18. #============================================================================
  19. # Scheduler 调度器属性配置
  20. #============================================================================
  21. # 调度标识名 集群中每一个实例都必须使用相同的名称
  22. org.quartz.scheduler.instanceName = ClusterQuartz
  23. # ID设置为自动获取 每一个必须不同
  24. org.quartz.scheduler.instanceId= AUTO
  25. #============================================================================
  26. # 配置ThreadPool
  27. #============================================================================
  28. # 线程池的实现类(一般使用SimpleThreadPool即可满足几乎所有用户的需求)
  29. org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
  30. # 指定线程数,一般设置为1-100直接的整数,根据系统资源配置
  31. org.quartz.threadPool.threadCount = 5
  32. # 设置线程的优先级(可以是Thread.MIN_PRIORITY(即1)和Thread.MAX_PRIORITY(这是10)之间的任何int 。默认值为Thread.NORM_PRIORITY(5)。)
  33. org.quartz.threadPool.threadPriority = 5

3.定义两个job

  • QuartzJob.java
  1. //持久化
  2. @PersistJobDataAfterExecution
  3. //禁止并发执行(Quartz不要并发地执行同一个job定义(这里指一个job类的多个实例))
  4. @DisallowConcurrentExecution
  5. @Slf4j
  6. public class QuartzJob extends QuartzJobBean {
  7. @Override
  8. protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
  9. String taskName = context.getJobDetail().getJobDataMap().getString("name");
  10. log.info("---> Quartz job {}, {} <----", new Date(), taskName);
  11. }
  12. }
  • QuartzJob2.java
  1. @PersistJobDataAfterExecution
  2. @DisallowConcurrentExecution
  3. @Slf4j
  4. public class QuartzJob2 extends QuartzJobBean {
  5. @Override
  6. protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
  7. String taskName = context.getJobDetail().getJobDataMap().getString("name");
  8. log.info("---> Quartz job 2 {}, {} <----", new Date(), taskName);
  9. }
  10. }

4.初始化触发器等信息,这里通过Listener初始化

  1. @Slf4j
  2. public class StartApplicationListener implements ApplicationListener<ContextRefreshedEvent> {
  3. @Autowired
  4. SchedulerConfig schedulerConfig;
  5. public static AtomicInteger count = new AtomicInteger(0);
  6. private static String TRIGGER_GROUP_NAME = "test_trriger";
  7. private static String JOB_GROUP_NAME = "test_job";
  8. @Override
  9. public void onApplicationEvent(ContextRefreshedEvent event) {
  10. // 防止重复执行
  11. if (event.getApplicationContext().getParent() == null && count.incrementAndGet() <= 1) {
  12. initMyJob();
  13. }
  14. }
  15. public void initMyJob() {
  16. Scheduler scheduler = null;
  17. try {
  18. scheduler = schedulerConfig.scheduler();
  19. TriggerKey triggerKey = TriggerKey.triggerKey("trigger1", TRIGGER_GROUP_NAME);
  20. CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
  21. if (null == trigger) {
  22. Class clazz = QuartzJob.class;
  23. JobDetail jobDetail = JobBuilder.newJob(clazz).withIdentity("job1", JOB_GROUP_NAME).build();
  24. CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?");
  25. trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", TRIGGER_GROUP_NAME)
  26. .withSchedule(scheduleBuilder).build();
  27. scheduler.scheduleJob(jobDetail, trigger);
  28. log.info("Quartz 创建了job:...:{}", jobDetail.getKey());
  29. } else {
  30. log.info("job已存在:{}", trigger.getKey());
  31. }
  32. TriggerKey triggerKey2 = TriggerKey.triggerKey("trigger2", TRIGGER_GROUP_NAME);
  33. CronTrigger trigger2 = (CronTrigger) scheduler.getTrigger(triggerKey2);
  34. if (null == trigger2) {
  35. Class clazz = QuartzJob2.class;
  36. JobDetail jobDetail2 = JobBuilder.newJob(clazz).withIdentity("job2", JOB_GROUP_NAME).build();
  37. CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/15 * * * * ?");
  38. trigger2 = TriggerBuilder.newTrigger().withIdentity("trigger2", TRIGGER_GROUP_NAME)
  39. .withSchedule(scheduleBuilder).build();
  40. scheduler.scheduleJob(jobDetail2, trigger2);
  41. log.info("Quartz 创建了job:...:{}", jobDetail2.getKey());
  42. } else {
  43. log.info("job已存在:{}", trigger2.getKey());
  44. }
  45. scheduler.start();
  46. } catch (Exception e) {
  47. log.info(e.getMessage());
  48. }
  49. }
  50. }

5.启动定时器

启动两个Application,分别是示例中的DemoQuartzApplication和DemoQuartzApplication2,会发现,两个Job会分别在两个应用执行。

当手动停止一个应用的时候,另一个应用会自动接管所有任务并继续执行,如果任务太多,我们可以再开一台服务即可。实现了调度任务的高可用性和可扩展性

运行效果如图:

资料

Spring Boot Quartz 分布式集群任务调度实现的更多相关文章

  1. Spring Boot MyBatis 数据库集群访问实现

    Spring Boot MyBatis 数据库集群访问实现 本示例主要介绍了Spring Boot程序方式实现数据库集群访问,读库轮询方式实现负载均衡.阅读本示例前,建议你有AOP编程基础.mybat ...

  2. spring结合Quartz的集群功能实现

    一:前沿 在上一篇(http://www.cnblogs.com/wuhao1991/p/4331613.html)的博客中记载了定时的功能,但是集成是没有成功的,在这篇中,我在解释下这里的”集成的含 ...

  3. Spring Boot集成Redis集群(Cluster模式)

    目录 集成jedis 引入依赖 配置绑定 注册 获取redis客户端 使用 验证 集成spring-data-redis 引入依赖 配置绑定 注册 获取redis客户端 使用 验证 异常处理 同样的, ...

  4. spring和Quartz的集群(二)

    一:前沿 写完了这两篇才突然想起来,忘记了最关键的东西,那就是在配置文件这里的配置,还有数据库的配置.这是郁闷啊!继续吧! 二:内容配置 我们在集成的时候需要自己配置一个quartz.properti ...

  5. Spring boot连接MongoDB集群

    主要问题是:MongoDB集群分为复制集(replicaSet)与分片集(shardingSet),那么如何去连接这两种集群: 参考官方文档,我使用了最通用的方法:通过构造connection str ...

  6. Quartz Spring分布式集群搭建Demo

    注:关于单节点的Quartz使用在这里不做详细介绍,直接进阶为分布式集群版的 1.准备工作: 使用环境Spring4.3.5,Quartz2.2.3,持久化框架JDBCTemplate pom文件如下 ...

  7. Kafka 完全分布式集群环境搭建

    思路: 先在主机s1上安装配置,然后远程复制到其它两台主机s2.s3上, 并分别修改配置文件server.properties中的broker.id属性. 1. 搭建前准备 示例共三台主机,主机IP映 ...

  8. MinIO分布式集群的扩展方案及实现

    目录 一.命令行方式扩展 1. MinIO扩展集群支持的命令语法 2. 扩容示例 二.etcd扩展方案 1. 环境变量 2. 运行多个集群 3. 示例 相关链接 MinIO 支持两种扩展方式: 通过修 ...

  9. #数据技术选型#即席查询Shib+Presto,集群任务调度HUE+Oozie

    郑昀 创建于2014/10/30 最后更新于2014/10/31   一)选型:Shib+Presto 应用场景:即席查询(Ad-hoc Query) 1.1.即席查询的目标 使用者是产品/运营/销售 ...

随机推荐

  1. ios webp转换jpg

    在项目开发的过程中,遇到了一个问题,就是webp的图片,先解释一下webp是啥,webp是谷歌开发的一种旨在加快图片加载速度的图片格式.图片压缩体积大约只有JPEG的2/3,说白了就是省空间,特别对于 ...

  2. 进程_Linux内核设计与实现笔记

    进程 进程是处于执行期的程序以及相关资源的总称,是正在执行的代码的实时结果. 进程部分位于Kernel的PM层.进程是Unix操作系统的抽象概念中最基本的一种,操作系统的存在就是为了运行用户程序,所以 ...

  3. PyCharm 2019.3激活破解教程(永久)

    2019.12.02 jetbrains公司发布了Python的最强编辑器PyCharm 2019.3版本.本次大版本主要对Jupyter notebooks .MongoDB.Python3.8功能 ...

  4. 使用cookies弹出层每24小时弹出一次

    第一步:下载cookies的库 https://github.com/js-cookie/js-cookie 第二步:设置Cookies的失效时间,这里有两种方法,按天计算和按小时计算 functio ...

  5. 华为云&#183;寻找黑马程序员#海量数据的分页怎么破?【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  6. Internet History,Technology,and Security - History Through Supercomputing(Week2)

    时间飞逝,一周又过去了,这周我们来到了Internet History, Technology and Security (Week 2)的学习,从标题就可以看出,这周主要是介绍“互联网”雏形的诞生. ...

  7. Unity3D for iOS初级教程:Part 1/3(下)

    转自:http://www.cnblogs.com/alongu3d/archive/2013/06/01/3111735.html 一个手指来统治他们 但是等等,你还没有完全完成! 如果你玩游戏有一 ...

  8. HDU 1808 Halloween treats

    Every year there is the same problem at Halloween: Each neighbour is only willing to give a certain ...

  9. promise 进阶 —— async / await 结合 bluebird

    一.背景 1.Node.js 异步控制 在之前写的 callback vs async.js vs promise vs async / await 里,我介绍了 ES6 的 promise 和 ES ...

  10. Spring Boot 外部化配置(一)- Environment、ConfigFileApplicationListener

    目录 前言 1.起源 2.外部化配置的资源类型 3.外部化配置的核心 3.1 Environment 3.1.1.ConfigFileApplicationListener 3.1.2.关联 Spri ...