关键词:
为什么要使用Quzrtz集群
在项目进行集群部署时,如果业务在执行中存在互斥关系,没有对定时任务进行统一管理,就会引起业务的多次执行,不能满足业务要求。这时就需要对任务进行管理,要保证一笔业务在所有的集群环境中,有且只有一台机器能执行该任务。
如果不适用Quartz集群,要如何实现这种业务逻辑?
在这里只列出两种简单的思路:
- 利用单线程机制。可以在redis中设置一个属性为空,每次任务执行时去设置这个全局变量,进入任务中需要对值进行校验,值不为空则跳过本次执行任务,值为空时进行设置,方法执行完毕后再将该值置空。
- 指定该定时任务在某台固定机器IP上执行,其他Ip则跳过该任务。
这两种方法都有其弊端,第一种是对代码侵入较大,第二种则是无法做到高可用。
准备工作
首先在http://www.quartz-scheduler.org/downloads/ 上下载quzrtz包,本文以quartz-2.3.0-distribution.tar.gz 版本为例。下载后解压,选择你需要的数据库进行表创建,本文以oracle为例,顾使用tables_oracle.sql即可。tips:可以直接在解压后 的文件夹里搜索table,就能找到支持的所有类型的数据库脚本。
核心代码实现
quartz.properties 基本配置属性
1 ###############内存版配置####################################
2 #org.quartz.scheduler.instanceName=spring-boot-quartz-demo
3 #org.quartz.scheduler.instanceId=AUTO
4 #org.quartz.threadPool.threadCount=5
5 #org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
6 ###############集群版配置####################################
7 org.quartz.scheduler.instanceName=spring-boot-quartz-demo
8 org.quartz.scheduler.instanceId=AUTO
9 org.quartz.scheduler.skipUpdateCheck=true
10 org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
11 org.quartz.threadPool.threadCount=5
12 org.quartz.threadPool.threadPriority=5
13 org.quartz.jobStore.misfireThreshold=60000
14 org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
15 #org.quartz.jobStore.dataSource=dataSource
16 org.quartz.jobStore.tablePrefix=QRTZ_
17 org.quartz.jobStore.isClustered=true
18 org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
19 org.quartz.jobStore.useProperties=false
QuartzJobFactory.java 注入到Spring 容器
package top.enjoyitlife.config;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;
import org.springframework.stereotype.Component;
@Component
public class QuartzJobFactory extends SpringBeanJobFactory
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
QuartzConfig.java 配置类 加载配置文件 对quartz进行实例化和属性设置 注意 使用集群方案 需要连接数据库,而内存版则不用配置数据库
package top.enjoyitlife.config;
import java.io.IOException;
import java.util.Properties;
import javax.sql.DataSource;
import org.quartz.spi.JobFactory;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
@Configuration
public class QuartzConfig
public static final String QUARTZ_PROPERTIES_PATH = "/quartz.properties";
@Bean
public JobFactory jobFactory(ApplicationContext applicationContext)
QuartzJobFactory jobFactory = new QuartzJobFactory();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
@Bean
public SchedulerFactoryBean schedulerFactoryBean(JobFactory jobFactory,DataSource dataSource, PlatformTransactionManager transactionManager) throws IOException
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setAutoStartup(true);
factory.setJobFactory(jobFactory);
factory.setQuartzProperties(quartzProperties());
//集群版配置
factory.setDataSource(dataSource);
factory.setTransactionManager(transactionManager);
return factory;
@Bean
public Properties quartzProperties() throws IOException
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource(QUARTZ_PROPERTIES_PATH));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
QuartzBindOperationConfig.java 定时任务的绑定 包括 触发器 CRON表达式 备注 任务名 任务所在组
package top.enjoyitlife.config;
import org.quartz.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import top.enjoyitlife.schedule.TestSchedule;
@Configuration
public class QuartzBindOperationConfig
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private QuartzJobFactory quartzJobFactory;
@Autowired
private Scheduler scheduler;
public void scheduleBind()
try
scheduler.setJobFactory(quartzJobFactory);
JobDetail tesJobDetail = JobBuilder.newJob(TestSchedule.class)
.withIdentity("tesJob", "tesJob").withDescription("定时任务demo")
.build();
CronScheduleBuilder tesJobCronScheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?");
CronTrigger tesJobCronTrigger = TriggerBuilder.newTrigger()
.withIdentity("tesJobTrigger", "tesJob")
.withSchedule(tesJobCronScheduleBuilder).build();
scheduler.scheduleJob(tesJobDetail, tesJobCronTrigger);
scheduler.start();
catch (SchedulerException e)
// e.printStackTrace();
ApplicationListenerConfig.java 项目启动初始化即加载任务
package top.enjoyitlife.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
@Configuration
public class ApplicationListenerConfig implements ApplicationListener<ContextRefreshedEvent>
private Logger logger = LoggerFactory.getLogger(getClass());
@Autowired
private QuartzBindOperationConfig quartzBindOperationConfig;
@Override
public void onApplicationEvent(ContextRefreshedEvent event)
quartzBindOperationConfig.scheduleBind();
TestSchedule.java 测试任务演示类
package top.enjoyitlife.schedule;
import java.util.Date;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@DisallowConcurrentExecution
public class TestSchedule implements Job
private Logger logger = LoggerFactory.getLogger(getClass());
@Override
public void execute(JobExecutionContext context) throws JobExecutionException
logger.info("*****"+new Date());
POM.xml 引用如下
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.4.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>top.enjoyitlife</groupId> <artifactId>enjoyitlife</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>quartzDistribute</name> <description>quartz集群demo</description> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <repositories> <repository> <id>maven-ali</id> <url>http://maven.aliyun.com/nexus/content/groups/public//</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> <updatePolicy>always</updatePolicy> <checksumPolicy>fail</checksumPolicy> </snapshots> </repository> </repositories> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <scope>provided</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.codehaus.janino</groupId> <artifactId>janino</artifactId> </dependency> <!-- 根据本地情况 进行对应调整--> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.4.0</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <version>1.3.5</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
运行日志:
2019-05-11 16:11:20.076 INFO 9624 --- [Quartz_Worker-1] top.enjoyitlife.schedule.TestSchedule : *****Sat May 11 16:11:20 CST 2019
2019-05-11 16:11:30.037 INFO 9624 --- [Quartz_Worker-2] top.enjoyitlife.schedule.TestSchedule : *****Sat May 11 16:11:30 CST 2019
2019-05-11 16:11:40.033 INFO 9624 --- [Quartz_Worker-3] top.enjoyitlife.schedule.TestSchedule : *****Sat May 11 16:11:40 CST 2019
任务执行后 数据库中就可以看到我对应的任务记录
集群效果验证
修改application.properties 中的server.port端口号,然后重新运行QuartzDistributeApplication的main 方法。以下截图为双服务同时启动时的任务,目前是只有任务1有日志记录,服务2没有任务记录。
停止任务1应用,然后我们会看到任务2 打印以下日志:
【小技巧】
如果要手动修改集群中的任务CRON 表达式,需要首先修改表QRTZ_CRON_TRIGGERS中的CRON_EXPRESSION表达式,然后在修改表QRTZ_TRIGGERS中的NEXT_FIRE_TIME和PREV_FIRE_TIME的值为0,在下次任务执行后,该任务的执行间隔就会生效。
如果要手动删除集群中的定时任务,删除表记录顺序如下:QRTZ_CRON_TRIGGERS----->QRTZ_TRIGGERS---->QRTZ_JOB_DETAILS,主要由于存在外键的原因,所以要按顺序删除。
springboot2.6.3集成quartz(代码片段)
....2.3这个版本,不知道为什么高版本的反而没有。集成Springboot代码yml配置spring:application:name:demo-exceldatasource:url:jdbc:mysq 查看详情
springboot2.6.3集成quartz(代码片段)
...#xff0c;不知道为什么高版本的反而没有,真是佛了集成Springboot代码yml配置spring:application:name:demo-exceldatasource:ur 查看详情
springboot集成quartz+mysql(代码片段)
Quartz简单使用JavaSpringBoot中,动态执行bean对象中的方法源代码地址=>https://gitee.com/VipSoft/VipBoot/tree/develop/vipsoft-quartz工作原理解读只要配置好DataSourceQuartz会自动进行表的数据操作,添加QuartzJob任务保存QRTZ_JOB_DETAILS、QRTZ_TRIGGERS=&g... 查看详情
springboot结合xxl-job实现定时任务(代码片段)
...文章工具比MyBatisGenerator更强大的代码生成器ORM框架选型SpringBoot项目基础设施搭建SpringBoot集成Mybatis项目实操SpringBoot集成MybatisPlus项目实操SpringBoot集成SpringDataJPA项目实操数据库变更管理数据库变更管理:LiquibaseorFlywaySpringBoot... 查看详情
quartz实战源码解析quartz分布式集群实现(代码片段)
...rtz实战】quartz-2.2.3源码分析和【Quartz实战】Quartz与Spring的集成,本篇从源码角度解析Quartz分布式集群实现。二、Quartz集群Quartz集群是基于数据库锁实现的,一个Quartz集群中的每个节点是一个独立的Quartz应用,它又管理... 查看详情
quartz实战源码解析quartz分布式集群实现(代码片段)
...rtz实战】quartz-2.2.3源码分析和【Quartz实战】Quartz与Spring的集成,本篇从源码角度解析Quartz分布式集群实现。二、Quartz集群Quartz集群是基于数据库锁实现的,一个Quartz集群中的每个节点是一个独立的Quartz应用,它又管理... 查看详情
springboot集成quartz实现任务调度
...模式组件模式链式写法体系结构调度器任务触发器架构图springbootquartzpom配置<dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</a 查看详情
springboot整合quartz实现动态的创建或删除定时任务并将定时调度任务持久化到mysql以及quartz集群配置(代码片段)
1.创建quartz数据库并导入quartz的SQL脚本文件quartz源码下载地址:http://www.quartz-scheduler.org/downloads/下载完成后解压,在/src/org/quartz/impl/jdbcjobstore可以找到对应数据库的SQL脚本我这里使用的是MySQL数据库,SQL脚本如下:... 查看详情
springboot整合quartz实现动态的创建或删除定时任务并将定时调度任务持久化到mysql以及quartz集群配置(代码片段)
1.创建quartz数据库并导入quartz的SQL脚本文件quartz源码下载地址:http://www.quartz-scheduler.org/downloads/下载完成后解压,在/src/org/quartz/impl/jdbcjobstore可以找到对应数据库的SQL脚本我这里使用的是MySQL数据库,SQL脚本如下:... 查看详情
quartz定时器知识概括(代码片段)
Quartz定时器知识概括Quartz简介Quartz简单入门Spring和Quartz集成SSMM和Quartz集成Quartz集群Quartz配置Quartz分布式Job与Tigger状态Quartz总结Quartz简介Quartz简介:Quartz是OpenSymphony开源组织在Jobscheduling领域又一个开源项目,是完全由java... 查看详情
minio单机集群搭建springboot集成,详细步骤(代码片段)
一、单机minio搭建1.下载rpm包下载地址:https://dl.min.io/server/minio/release/linux-amd64/ 2.安装rpm-ivhminio-20220504074527.0.0.x86_64.rpm 修改/etc/systemd/system/minio.service文件#启动的用户和用户组User=rootGroup= 查看详情
springboot整合quartz实现动态的创建或删除定时任务并将定时调度任务持久化到mysql以及quartz集群配置(代码片段)
1.创建quartz数据库并导入quartz的SQL脚本文件quartz源码下载地址:http://www.quartz-scheduler.org/downloads/下载完成后解压,在/src/org/quartz/impl/jdbcjobstore可以找到对应数据库的SQL脚本我这里使用的是MySQL数据库,SQL脚本如下:... 查看详情
springboot+quartz集群
springbootbean配置:@ConfigurationpublicclassQuartzConfig{ @Value("${quartz.scheduler.instanceName}") privateStringquartzInstan 查看详情
springboot整合quartz集群环境实现动态定时任务配置原
最近做了一个springboot 整合quartz 实现动态定时任务配置,在集群环境下运行的任务。能够对定时任务,动态的进行增删改查,界面效果图如下: 1.在项目中引入jar 2.将需要的表导入数据库 官网上有不... 查看详情
quartz实战源码解析quartz分布式集群实现(代码片段)
...rtz实战】quartz-2.2.3源码分析和【Quartz实战】Quartz与Spring的集成,本篇从源码角度解析Quartz分布式集群实现。二、Quartz集群Quartz集群是基于数据库锁实现的,一个Quartz集群中的每个节点是一个独立的Quartz应用,它又管理... 查看详情
springboot入门:集成quartz定时任务
本片文章续《SpringBoot入门(八):集成RabbitMQ消息队列》,关于Quartz定时任务请参考《Quartz的基本使用之入门(2.3.0版本)》springboot实现定时任务,除了集成Quartz外,还可以直接使用scheduler注解。使用1个简单的注解就可以完成... 查看详情
springboot集成hadoop(代码片段)
SpringBoot集成Hadoop,相关配置过程如下。默认在Linux下已经装好Hadoop集群(Hadoop-2.8.5)。一、集成HDFS1、主要application.properties配置#hdfshdfs.url=hdfs://192.168.2.5:9000hdfs.username=roothdfs.replication 查看详情
springboot集成springsession(代码片段)
10.1分布式集群环境下的集成(同域名、同项目)10.1.1 创建SpringBoot的web支持项目07-springboot-session创建项目10.1.2 在pom.xml文件中添加依赖<!--配置springsessi 查看详情