springboot整合quartz实现分布式定时任务集群

springboot-整合quartz:做分布式定时任务 springboot-整合quartz:做分布式定时任务 文章目录springboot-整合quartz:做分布式定时任务1.quartz应用场景2配置3.测试 完整代码下载链接: https://github.com/2010yhh/springBoot-demos.git 环境 idea2018,jdk1.8, springboot版本:springboot1.5.9.RELEASE, 1... 阅读详情

springboot整合quartz实现分布式定时任务集群

文章参考1:https://blog.youkuaiyun.com/fyfguuug/article/details/79358159
文章参考2:https://blog.youkuaiyun.com/qq_41866572/article/details/80061853
文章参考3:https://blog.youkuaiyun.com/wanghaoalain/article/details/79288387
文章参考4:https://blog.youkuaiyun.com/chenyao1994/article/details/80482053
实现job的操作:https://blog.youkuaiyun.com/lfy609225258/article/details/96105538
感谢作者!

什么是quartz

如果仅仅只是使用定时任务,可以使用spring的schedule实现,方便,代码量少.易于实现,但是,思考一个问题.
当使用分布式进行项目部署的时候,每一哥jar包中都包含一个定时任务,就会出现所有的服务器都在跑同一个定时,出现一个定时任务执行多次的情况,会出现很多问题.
最简单的解决方式,改项目,只留一个项目存在定时任务,其他都没有,但是,这样就会出现单点故障的问题.并不是最好的解决方式.
最好的方式是,使用quartz进行定时任务的调度.

quartz的优点:

1.我们可以实现多个定时任务进行调度。

2.可以实现与代码的解耦,通过配置文件的方式进行配置。

3.功能强大,可以通过cron表达式设置复杂的时间任务调度。

quartz核心点:

1.job:(被任务调度的接口),我们需要实现job,和继承TimerTask重写run方法一样,重写job中的excute方法,excute方法是任务调度的方法执行位置。

2.JobDetail:必须通过JobDetail来实现Job实例,(基于builder模式实现的)

3.trigger(包括:CronTrigger 和simpleTrigger):指定任务调度的频率时间。何时进行任务调度(基于builder模式实现的)触发器

4.scheduler:结合jobdetail 实例和trigger实例,进行调度的触发的调度器(基于factory模式)。

Quartz 中集群如何工作

一个 Quartz 集群中的每个节点是一个独立的 Quartz 应用,它又管理着其他的节点。意思是你必须对每个节点分别启动或停止。不像许多应用服务器的集群,独立的 Quartz 节点并不与另一其的节点或是管理节点通信。Quartz 应用是通过数据库表来感知到另一应用的。离开了db将无法感知.
在这里插入图片描述

实现

1.导入数据库表

因为Quartz 集群依赖于数据库,所以必须首先创建Quartz数据库表。Quartz 包括了所有被支持的数据库平台的 SQL 脚本。这是mysql的表.
注意:创建的表表名都是小写的,在代码中使用的是大写的表名;在liunx中的mysql数据库默认是大小写敏感的,因此使用liunx的数据库会出现找不到表的情况,酌情修改表或是改变数据库配置

Caused by: java.sql.SQLSyntaxErrorException: Table 'schedule_quartz.QRTZ_TRIGGERS' doesn't exist
	at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:120) ~[mysql-connector-java-8.0.17.jar:8.0.17]

表中所有字段详解: https://blog.youkuaiyun.com/sqlgao22/article/details/100697214
所有资源地址: https://download.youkuaiyun.com/download/sqlgao22/11705738

/*
Navicat MySQL Data Transfer
Source Server         : 192.168.163.128_3306
Source Server Version : 50540
Source Host           : 192.168.163.128:3306
Source Database       : primer
Target Server Type    : MYSQL
Target Server Version : 50540
File Encoding         : 65001
Date: 2018-08-29 22:56:23
*/

SET FOREIGN_KEY_CHECKS=0;
-- ----------------------------
-- Table structure for qrtz_blob_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_blob_triggers`;
CREATE TABLE `qrtz_blob_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_NAME` varchar(200) NOT NULL,
  `TRIGGER_GROUP` varchar(200) NOT NULL,
  `BLOB_DATA` blob,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `SCHED_NAME` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  CONSTRAINT `qrtz_blob_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_calendars
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_calendars`;
CREATE TABLE `qrtz_calendars` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `CALENDAR_NAME` varchar(200) NOT NULL,
  `CALENDAR` blob NOT NULL,
  PRIMARY KEY (`SCHED_NAME`,`CALENDAR_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_cron_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_cron_triggers`;
CREATE TABLE `qrtz_cron_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_NAME` varchar(200) NOT NULL,
  `TRIGGER_GROUP` varchar(200) NOT NULL,
  `CRON_EXPRESSION` varchar(120) NOT NULL,
  `TIME_ZONE_ID` varchar(80) DEFAULT NULL,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  CONSTRAINT `qrtz_cron_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_fired_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_fired_triggers`;
CREATE TABLE `qrtz_fired_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `ENTRY_ID` varchar(95) NOT NULL,
  `TRIGGER_NAME` varchar(200) NOT NULL,
  `TRIGGER_GROUP` varchar(200) NOT NULL,
  `INSTANCE_NAME` varchar(200) NOT NULL,
  `FIRED_TIME` bigint(13) NOT NULL,
  `SCHED_TIME` bigint(13) NOT NULL,
  `PRIORITY` int(11) NOT NULL,
  `STATE` varchar(16) NOT NULL,
  `JOB_NAME` varchar(200) DEFAULT NULL,
  `JOB_GROUP` varchar(200) DEFAULT NULL,
  `IS_NONCONCURRENT` varchar(1) DEFAULT NULL,
  `REQUESTS_RECOVERY` varchar(1) DEFAULT NULL,
  PRIMARY KEY (`SCHED_NAME`,`ENTRY_ID`),
  KEY `IDX_QRTZ_FT_TRIG_INST_NAME` (`SCHED_NAME`,`INSTANCE_NAME`),
  KEY `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY` (`SCHED_NAME`,`INSTANCE_NAME`,`REQUESTS_RECOVERY`),
  KEY `IDX_QRTZ_FT_J_G` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_FT_JG` (`SCHED_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_FT_T_G` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_QRTZ_FT_TG` (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_job_details
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_job_details`;
CREATE TABLE `qrtz_job_details` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `JOB_NAME` varchar(200) NOT NULL,
  `JOB_GROUP` varchar(200) NOT NULL,
  `DESCRIPTION` varchar(250) DEFAULT NULL,
  `JOB_CLASS_NAME` varchar(250) NOT NULL,
  `IS_DURABLE` varchar(1) NOT NULL,
  `IS_NONCONCURRENT` varchar(1) NOT NULL,
  `IS_UPDATE_DATA` varchar(1) NOT NULL,
  `REQUESTS_RECOVERY` varchar(1) NOT NULL,
  `JOB_DATA` blob,
  PRIMARY KEY (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_J_REQ_RECOVERY` (`SCHED_NAME`,`REQUESTS_RECOVERY`),
  KEY `IDX_QRTZ_J_GRP` (`SCHED_NAME`,`JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_locks
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_locks`;
CREATE TABLE `qrtz_locks` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `LOCK_NAME` varchar(40) NOT NULL,
  PRIMARY KEY (`SCHED_NAME`,`LOCK_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_paused_trigger_grps
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_paused_trigger_grps`;
CREATE TABLE `qrtz_paused_trigger_grps` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_GROUP` varchar(200) NOT NULL,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_scheduler_state
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_scheduler_state`;
CREATE TABLE `qrtz_scheduler_state` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `INSTANCE_NAME` varchar(200) NOT NULL,
  `LAST_CHECKIN_TIME` bigint(13) NOT NULL,
  `CHECKIN_INTERVAL` bigint(13) NOT NULL,
  PRIMARY KEY (`SCHED_NAME`,`INSTANCE_NAME`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_simple_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_simple_triggers`;
CREATE TABLE `qrtz_simple_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_NAME` varchar(200) NOT NULL,
  `TRIGGER_GROUP` varchar(200) NOT NULL,
  `REPEAT_COUNT` bigint(7) NOT NULL,
  `REPEAT_INTERVAL` bigint(12) NOT NULL,
  `TIMES_TRIGGERED` bigint(10) NOT NULL,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  CONSTRAINT `qrtz_simple_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_simprop_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_simprop_triggers`;
CREATE TABLE `qrtz_simprop_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_NAME` varchar(200) NOT NULL,
  `TRIGGER_GROUP` varchar(200) NOT NULL,
  `STR_PROP_1` varchar(512) DEFAULT NULL,
  `STR_PROP_2` varchar(512) DEFAULT NULL,
  `STR_PROP_3` varchar(512) DEFAULT NULL,
  `INT_PROP_1` int(11) DEFAULT NULL,
  `INT_PROP_2` int(11) DEFAULT NULL,
  `LONG_PROP_1` bigint(20) DEFAULT NULL,
  `LONG_PROP_2` bigint(20) DEFAULT NULL,
  `DEC_PROP_1` decimal(13,4) DEFAULT NULL,
  `DEC_PROP_2` decimal(13,4) DEFAULT NULL,
  `BOOL_PROP_1` varchar(1) DEFAULT NULL,
  `BOOL_PROP_2` varchar(1) DEFAULT NULL,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  CONSTRAINT `qrtz_simprop_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `qrtz_triggers` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for qrtz_triggers
-- ----------------------------
DROP TABLE IF EXISTS `qrtz_triggers`;
CREATE TABLE `qrtz_triggers` (
  `SCHED_NAME` varchar(120) NOT NULL,
  `TRIGGER_NAME` varchar(200) NOT NULL,
  `TRIGGER_GROUP` varchar(200) NOT NULL,
  `JOB_NAME` varchar(200) NOT NULL,
  `JOB_GROUP` varchar(200) NOT NULL,
  `DESCRIPTION` varchar(250) DEFAULT NULL,
  `NEXT_FIRE_TIME` bigint(13) DEFAULT NULL,
  `PREV_FIRE_TIME` bigint(13) DEFAULT NULL,
  `PRIORITY` int(11) DEFAULT NULL,
  `TRIGGER_STATE` varchar(16) NOT NULL,
  `TRIGGER_TYPE` varchar(8) NOT NULL,
  `START_TIME` bigint(13) NOT NULL,
  `END_TIME` bigint(13) DEFAULT NULL,
  `CALENDAR_NAME` varchar(200) DEFAULT NULL,
  `MISFIRE_INSTR` smallint(2) DEFAULT NULL,
  `JOB_DATA` blob,
  PRIMARY KEY (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_QRTZ_T_J` (`SCHED_NAME`,`JOB_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_T_JG` (`SCHED_NAME`,`JOB_GROUP`),
  KEY `IDX_QRTZ_T_C` (`SCHED_NAME`,`CALENDAR_NAME`),
  KEY `IDX_QRTZ_T_G` (`SCHED_NAME`,`TRIGGER_GROUP`),
  KEY `IDX_QRTZ_T_STATE` (`SCHED_NAME`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_N_STATE` (`SCHED_NAME`,`TRIGGER_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_N_G_STATE` (`SCHED_NAME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_NEXT_FIRE_TIME` (`SCHED_NAME`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_ST` (`SCHED_NAME`,`TRIGGER_STATE`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`),
  KEY `IDX_QRTZ_T_NFT_ST_MISFIRE` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_STATE`),
  KEY `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP` (`SCHED_NAME`,`MISFIRE_INSTR`,`NEXT_FIRE_TIME`,`TRIGGER_GROUP`,`TRIGGER_STATE`),
  CONSTRAINT `qrtz_triggers_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `qrtz_job_details` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

引入pom依赖

        <!-- quartz定时器 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>
        <!--druid连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>

引入quartz.properties配置

这里要注意,使用分布式集群跑定时,需要使用到db持久化,所以需要所有的节点共享一个数据源.
关键配置都有注释.

#============================================================================
# Configure JobStore
# Using Spring datasource in SchedulerConfig.java
# Spring uses LocalDataSourceJobStore extension of JobStoreCMT
#============================================================================
org.quartz.jobStore.useProperties=false
#表名的前缀
org.quartz.jobStore.tablePrefix = QRTZ_
#isClustered 属性为 true,你就告诉了 Scheduler 实例要它参与到一个集群当中
org.quartz.jobStore.isClustered = true
#clusterCheckinInterval 属性定义了Scheduler 实例检入到数据库中的频率(单位:毫秒),默认值是 15000
org.quartz.jobStore.clusterCheckinInterval = 3000
org.quartz.jobStore.misfireThreshold = 60000
org.quartz.jobStore.txIsolationLevelReadCommitted = true
#class属性为 JobStoreTX,将任务持久化到数据中。quartz依赖于数据库查询任务状态
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

#============================================================================
# Configure Main Scheduler Properties
# Needed to manage cluster instances
#============================================================================
#instanceName属性可为任何值,用在 JDBC JobStore 中来唯一标识实例,但是所有集群节点中必须相同。
org.quartz.scheduler.instanceName = ClusterQuartz
#instanceId 属性为 AUTO即可,基于主机名和时间戳来产生实例 ID
org.quartz.scheduler.instanceId= AUTO
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = false

#============================================================================
# Configure ThreadPool
# Can also be configured in spring configuration
# 此处使用的java的线程池
#============================================================================
#org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
#org.quartz.threadPool.threadCount = 5
#org.quartz.threadPool.threadPriority = 5
#org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true

springboot的配置类

几乎每行代码都有详细的注释.这边就不详细写了.请看代码.

package com.jd.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.jd.task.SimpleJob;
import com.jd.task.SimpleJobTwo;
import org.quartz.Scheduler;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.Executor;

@Configuration
public class TaskConfig {

    //配置数据源
    //这里可以不使用@Bean交给spring管理,否则可能出现默认数据源的问题.
    //@Bean
    public DataSource druidDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/schedule?serverTimezone=GMT%2B8");
        dataSource.setUsername("root");
        dataSource.setPassword("112233");
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        return dataSource;
    }

    //配置quartz配置文件
    @Bean
    public Properties quartzProperties() throws IOException {
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        // 在quartz.properties中的属性被读取并注入后再初始化对象
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }

    //配置定时任务1
    @Bean
    public JobDetailFactoryBean job1() {
        JobDetailFactoryBean jobDetail = new JobDetailFactoryBean();
        //配置任务的具体实现
        jobDetail.setJobClass(SimpleJob.class);
        //是否持久化
        jobDetail.setDurability(true);
        //出现异常是否重新执行
        jobDetail.setRequestsRecovery(true);
        //配置定时任务信息
        jobDetail.setName("job1111------");
        jobDetail.setGroup("quartzTest--------");
        jobDetail.setDescription("这是job1111");
        return jobDetail;
    }

    //配置定时任务2
    @Bean
    public JobDetailFactoryBean job2() {
        JobDetailFactoryBean jobDetail = new JobDetailFactoryBean();
        jobDetail.setJobClass(SimpleJobTwo.class);
        jobDetail.setDurability(true);
        jobDetail.setRequestsRecovery(true);
        jobDetail.setName("job22222------");
        jobDetail.setGroup("quartzTest--------");
        jobDetail.setDescription("这是job2222");
        return jobDetail;
    }

    //配置任务定时规则1
    @Bean
    public CronTriggerFactoryBean trigger1() {
        CronTriggerFactoryBean cronTrigger = new CronTriggerFactoryBean();
        //定时规则的分组
        cronTrigger.setGroup("TriggerTest11111");
        cronTrigger.setName("trigger1");
        //配置执行的任务jobdetail
        cronTrigger.setJobDetail(job1().getObject());
        //配置执行规则 每5秒执行一次
        cronTrigger.setCronExpression("0/5 * * * * ?");
        return cronTrigger;
    }

    //配置任务定时规则2
    @Bean
    public CronTriggerFactoryBean trigger2() {
        CronTriggerFactoryBean cronTrigger = new CronTriggerFactoryBean();
        cronTrigger.setGroup("TriggerTest2222");
        cronTrigger.setName("trigger2");
        cronTrigger.setJobDetail(job2().getObject());
        cronTrigger.setCronExpression("0/8 * * * * ?");
        return cronTrigger;
    }


    //配置任务调度工厂,用来生成任务调度器,这是quartz的核心
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        //开启更新job
        factory.setOverwriteExistingJobs(true);
        //如果不配置就会使用quartz.properties中的instanceName
        //factory.setSchedulerName("Cluster_Scheduler");
        //配置数据源,这是quartz使用的表的数据库存放位置
        factory.setDataSource(druidDataSource());
        //设置实例在spring容器中的key
        factory.setApplicationContextSchedulerContextKey("applicationContext");
        //配置线程池
        factory.setTaskExecutor(schedulerThreadPool());
        //配置配置文件
        factory.setQuartzProperties(quartzProperties());
        //配置任务执行规则,参数是一个可变数组
        factory.setTriggers(trigger1().getObject(),trigger2().getObject());
        return factory;
    }
    //开启当前的任务调度器
    @Bean
    public Scheduler scheduler() throws Exception {
        Scheduler scheduler = schedulerFactoryBean().getScheduler();
        TriggerKey triggerKey1 = TriggerKey.triggerKey("trigger1", "TriggerTest11111");
        /*========如果有必要可以配置删除任务,开始====================*/
        //停止触发器
        scheduler.pauseTrigger(triggerKey1);
        //移除触发器
        scheduler.unscheduleJob(triggerKey1);
        JobKey jobKey1 = JobKey.jobKey("job1111------", "quartzTest--------");
        //删除任务
        boolean b = scheduler.deleteJob(jobKey1);
        System.out.println(b);
        /*=========结束====================*/
        scheduler.start();
        return scheduler;
    }

    //线程池配置
    @Bean
    public Executor schedulerThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(20);
        executor.setQueueCapacity(50);
        return executor;
    }
}

编写定时任务

定时任务需要实现job接口,但是quartz已经有了一个简单的抽象实现,简化了代码量.只需要直接继承即可.
这里贴一下源代码,一开始看资料有实现job接口的,有继承QuartzJobBean 的,没看太懂,后来看源码才知道了.

	public abstract class QuartzJobBean implements Job 

写定时任务:

第一个定时任务
@Component
public class SimpleJob extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("=========SimpleJob中的executeInternal方法执行了===="+new Date());
    }
}
第二个定时任务
@Component
public class SimpleJobTwo extends QuartzJobBean {
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        System.out.println("-----------------SimpleJobTwo的任务执行了------"+new Date());
    }
}

测试

先测试定时任务

启动项目:
输出:说明定时任务没有问题
在这里插入图片描述

再测试多项目

将项目打成jar包,运行.
将原项目改端口,重新运行.
当只有一个项目的时候,两个会在同一个上执行,如上图.
当两个启动时:
会进行分开进行:
在这里插入图片描述
在这里插入图片描述

同时数据库中出现两个项目的信息:
在这里插入图片描述

总结

解决了单点故障,也能执行定时.

实际使用中的问题

当在定时任务的job中进行属性注入的时候就会发现所有的对象都无法使用Autowired进行注入,会有空指针异常抛出.
java.lang.NullPointerException: null
	at com.jd.jrdp.agile.bi.service.task2.CheckExportOverDueSchedulerJob.checkExportData(CheckExportOverDueSchedulerJob.java:38) ~[classes!/:na]
	at com.jd.jrdp.agile.bi.service.task2.CheckExportOverDueSchedulerJob.executeInternal(CheckExportOverDueSchedulerJob.java:56) ~[classes!/:na]
原因

Quartz初始化是自己的JobContext,不同于Spring的ApplicationContext,所以无法直接注入,导致使用时产生空指针异常!
版本也有关系:
spring3.1以下的版本必须使用quartz1.x系列,3.1以上的版本才支持quartz 2.x,不然会出错。至于原因,则是spring对于quartz的支持实现org.springframework.scheduling.quartz.CronTriggerBean继承了org.quartz.CronTrigger,在quartz1.x系列中org.quartz.CronTrigger是个类,而在quartz2.x系列中org.quartz.CronTrigger变成了接口,从而造成无法用spring的方式配置quartz的触发器(trigger)。

解决方式

自定义一个类.继承JobFactory.重写createInstance方法,

@Component
public class MyJobFactory extends SpringBeanJobFactory {
    @Autowired
    //注入autowire的对象工厂
    private AutowireCapableBeanFactory beanFactory;
    //重写Job工厂的createJobInstance方法
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object object = super.createJobInstance(bundle);
        //在autowired中手动加入创建出来的对象
        beanFactory.autowireBean(object);
        return object;
    }
}

注意配置类中的变化:
需要在调度中心SchedulerFactoryBean中额外配置使用自己的JobFactory,以及配置延迟加载.

	//将自定义的MyJobFactory注入配置类,并添加如下配置,
        //配置使用spring的autowired的对象,在job中进行对象的注入
        factory.setJobFactory(jobFactory);
        //设置延时启动,保证job中的属性的注入
        factory.setStartupDelay(5);

到此为止,问题就解决了.

SpringBoot整合Quartz 实现分布式定时任务调度 一、Quartz集群架构 Quartz 是 Java 领域最著名的开源任务调度工具。 在上篇文章中,我们详细的介绍了 Quartz 的单体应用实践,如果只在单体环境中应用,Quartz 未必是最好的选择,例如Spring Scheduled一样也可以实现任务调度,并且与SpringBoot无缝集成,支持注解配置,非常简单,但是它有个缺点就是在集群环境下,会导致任务被重复调度! 而与之对应的 Quartz 提供了极为广用的特性,如任务持久化、集群部署和分布式调度任务等等,正因如此,基于 Quartz . 阅读详情

相关推荐

Springboot整合quartz实现分布式定时任务

Quartz提供两种基本作业存储类型: RAMJobStore :RAM也就是内存,默认情况下Quartz会将任务调度存在内存中,这种方式性能是最好的,因为内存的速度是最快的。不好的地方就是数据缺乏持久性,但程序崩溃或者重新发布的时候,所有运行信息都会丢失 JDBC作业存储:存到数据库之后,可以做单点也可以做集群,当任务多了之后,可以统一进行管理。关闭或者重启服务器,运行的信息都不会丢失。缺点就是运行速度快慢取决于连接数据库的快慢。 使用JDBC作业存储的方式,第一次启动后定时任务会自动写入到数据库。再

859

Spring Boot Quartz 分布式集群任务调度实现

Spring Boot Quartz 主要内容 Spring Scheduler 框架 Quartz 框架,功能强大,配置灵活 Quartz 集群 mysql 持久化定时任务脚本(tables_mysql.sql) 介绍 在工程中时常会遇到一些需求,例如定时刷新一下配置、隔一段时间检查下网络状态并发送邮件等诸如此类的定时任务。 定时任务本质就是一个异步的线程,线程可以查询或修改并执行一系列的操作。由于本质是线程,在 Java 中可以自行编写一个线程池对定时任务进行控制,但这样效率太低了,且功能有

DN金猿的博客 623

Quartz + SpringBoot 实现分布式定时任务

Quartz + SpringBoot 实现分布式定时任务

weixin_44111939的博客 1814

spring boot下定时任务quartz的集群使用

单机模式下的定时任务调用很简单,有很多可实现的方案,这里不多说了。 这里说一下集群部署的情况下,定时任务的使用。这种情况下,quartz是一个比较好的选择。简单,稳定。 想象一下,现在有 A , B , C  3 台机器同时作为集群服务器对外统一提供 SERVICE : A , B , C   3 台机器上各有一个 QUARTZ  Job,它们会按照即定的 SCHEDULE 自动执行

Gogym的博客 1万+

【MCU开发规范】:车载MCU开发规范

车载MCU开发规范

1047

从零开始:如何用Python手绘波特图并分析电路稳定性

本文详细介绍了如何使用Python绘制波特图并分析电路稳定性,涵盖从基础理论到实际应用的完整流程。通过NumPy和Matplotlib实现频域分析,包括RC低通滤波器和RLC带通滤波器的案例,以及相位裕度计算等高级技巧,为电子工程师提供了一套高效的电路分析解决方案。

hhh00的博客 369

springboot整合quartz(集群环境)

使用quartz实现定时任务,若是部署多台机器,那么到了时间点,多台服务器便会同时均开始执行定时任务,这不符合我们的功能实现。     quartz集群分为水平集群和垂直集群,水平集群即将定时任务节点部署在不同的服务器,其最大的问题就是时钟同步问题,若时钟不能同步,则会导致集群中各个节点状态紊乱,造成不可预知的后果;垂直集群则是集群各节点部署在同一台服务器,时钟同步自然不是问题,但存在单点故障问题...

weixin_42649194的博客 373

在Mac上搭建本地AI工作流:Dify与DeepSeek的完美结合

本文介绍了在Mac上搭建本地AI工作流的方法,结合Dify平台和DeepSeek模型。Dify是一个开源的大语言模型应用开发平台,支持可视化AI应用开发。部署步骤包括:1)安装Homebrew和Docker;2)克隆Dify代码库;3)配置环境变量并启动服务。同时,使用Ollama工具本地部署DeepSeek模型,将其集成到Dify中创建聊天助手。通过配置模型接口和新建应用,用户可以在本地环境中实现AI对话功能。这种方案既保证了数据隐私,又提供了灵活的AI应用开发能力。

Linda的自动化测试之旅 1535

定时任务调度框架Quartz--SpringBoot使用Quartz并使用集群配置

文章目录基本配置导入依赖基本配置文件quartz.properties配置ScheduleFactoryBean与生成Job实例工厂 基本配置 导入依赖         Quartz版本得话会跟着SpringBoot项目走 <dependency> <groupId>org.springframework.boot</groupId>

大宇的博客,欢迎访问 2442

一个完整的c#股票分析软件源码

完整的c#股票分析软件源码

qq_35600909的博客 4595

【开源】基于TI ADS1299与ESP32的8通道脑电采集设备YuEEG全解析

本文详细解析了基于TI ADS1299芯片与ESP32主控的开源8通道脑电采集设备YuEEG。内容涵盖硬件设计、固件驱动开发及Python上位机软件实现,提供了从电路连接、SPI通信配置到数据读取与实时波形显示的全套教程。该项目为学习脑机接口(BCI)与高精度生物电信号采集提供了完整的开源解决方案,适合创客、学生及嵌入式开发者实践。

weixin_42576410的博客 1234

Springboot+Quartz集群配置

看了一些网上的文章,都不太合我意,集众家之长,来个自己的版本。原理和介绍就不搬来搬去了,直接上代码吧。 目录 一.POM文件 二.application-quartz.properties 三.java文件 3.1Application 3.2QuartzSchedulerConfig配置一下,类名自己随便改 3.3 StartApplicationListener应用启动时调用一下QuartzTasks添加定时任务 3.4QuartzTasks...

浪子天涯行世录 5517

YOLOv9实战:刀具磨损实时监控从摄像头到预测性维护(附车间落地代码)

摘要: 本文针对制造业刀具磨损监控痛点,提出基于YOLOv9的实时视觉检测方案。通过工业相机采集刀具图像,结合图像预处理(去油污、增强对比度)和深度学习模型,实现磨损等级分类与寿命预测。系统集成硬件选型(抗油污相机、红色环形光源)、数据增强(旋转、噪声模拟)及预测性维护(PLC联动),实测刀具利用率提升30%,工件报废率降至0.5%以下。详解车间部署、模型训练到系统落地的全流程,附代码与避坑指南,为工业视觉项目提供实战参考。

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 541

SpringBoot 整合Quartz实现分布式集群定时任务

SpringBoot 整合Quartz实现分布式集群定时任务 (icode9.com)

m0_55876338的博客 302

嵌入式面经篇八——进程&线程

记录一些招聘公司在招聘嵌入式软件岗位时的一些问题,此文为第八篇。进程上文:是指进程由用户态切换到内核态时需要保存用户态时CPU寄存器中的值,进程状态以及堆栈上的内容。即保存当前进程的状态,以便再次执行该进程时,能够恢复切换时的状态,继续执行。进程下文:是指切换到内核态后执行的程序,即进程运行在内核空间的部分。中断上文:硬件通过中断触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理。

明天你好的博客 1854

超声相控阵合成孔径成像FPGA设计介绍

1.仿真预览 2.理论分析 系统的基本结构如下所示: 以上是实际中完整的结构,系统中会涉及到两块板子中的时钟,这个就是设计一个时钟采样同步的问题,即所谓的时钟同步。一般这种情况,往往使用内插的方式来解决。这是由于,在实际中,超生波接收到的信号是由本身系统发送出去反射回来得到的,因此从另外一方面将,其是同步的。但是在接收的时候通过内插的方法解决其中的延迟问题。 根据论文中的介绍,整个系统分为如下几个部分: ·模拟发送信号,这个部分由MATLAB产生测试数据并量...

FPGA/MATLAB学习教程/源码/项目合作开发 2069

SpringBoot2.1.0整合Quartz实现分布式集群定时任务

项目使用springboot,一直是单机版,所以也就一直使用springboot整合task的方式,用起来简单方便,但是最近项目改为多节点部署,用一个模块部署在多个机器,这样就会导致以前的定时任务重复执行. 所以本文正是在了解到quartz可以实现分布式定时任务后,对quart做了简单的使用,并整理成博客,以前也有用过spring与quartz的整合,通过xml与properties配置文件,但...

success_123的博客 2893

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

SpringBoot整合Quartz实现分布式集群定时任务

java定时器

Be yourself,everyone else is already taken 801

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

springboot项目整合分布式定时任务quartz详解

Quartz是OpenSymphony开源组织在Job scheduling领域的一个开源项目,不同于Spring 自带的Scheduled,Quartz可以实现集群部署和分布式调度任务,从而避免在集群环境下,会导致任务被重复调度的问题,在多服务节点下,每一个节点上的quartz都是一个独立的应用。通过数据库锁的方式来保证每个节点的任务只有一个运行。

m0_66389650的博客 1255

Springboot 整合 Quartz(定时任务框架)

Quartz是 OpenSymphony 开源组织在 Job scheduling 领域又一个开源项目,完全由 Java 开发,可以用来执行定时任务,类似于 java.util.Timer。持久性作业 - 就是保持调度定时的状态;作业管理 - 对调度作业进行有效的管理;

2509_94006401的博客 877

两个quartz访问同一数据库_SpringBoot+Quartz定时任务快速入门

在前面的文章中,我们已实现了在 SpringBoot 项目中执行定时任务第三十二章:配置定时任务但是,自带的定时任务有其局限性,比如在分布式环境中无法协调多节点,就会导致一个任务会在多个节点同时执行。接下来,我们将实现对开源作业调度框架 Quartz 的整合。相关知识什么是 QuartzQuartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却...

weixin_39604045的博客 254

SpringBoot定时任务实现方式+Quartz

SpringbootQuartz是开源组织在领域又一个开源项目,是完全由Java开发的一个开源任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。Quartz是一个开源的作业调度,它完全由Java写成,并设计用于J2SE和J2EE应用中,它提供了巨大的灵活性而不牺牲简单性当定时任务愈加复杂时,使用Spring注解@Schedule已经不能满足业务需要。........................

Java后端技术栈 1386

Springboot 整合Quartz

springboot整合quartz相关基本配置

yang_fei9264的博客 8119
上一篇: @Autowired无法注入,异常:NullPointerException: null
下一篇: quartz中表及其表字段的意义
黑白格tt
博客等级 码龄8年 35粉丝 45原创
评论 6
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值