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

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

文章参考1:https://blog.csdn.net/fyfguuug/article/details/79358159
文章参考2:https://blog.csdn.net/qq_41866572/article/details/80061853
文章参考3:https://blog.csdn.net/wanghaoalain/article/details/79288387
文章参考4:https://blog.csdn.net/chenyao1994/article/details/80482053
实现job的操作:https://blog.csdn.net/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将无法感知.
springboot整合quartz实现分布式定时任务集群_第1张图片

实现

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.csdn.net/sqlgao22/article/details/100697214
所有资源地址: https://download.csdn.net/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依赖

        
        
            org.springframework
            spring-context-support
        
        
            org.quartz-scheduler
            quartz
            2.3.0
        
        
        
            com.alibaba
            druid
            1.1.12
        

引入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());
    }
}

测试

先测试定时任务

启动项目:
输出:说明定时任务没有问题
springboot整合quartz实现分布式定时任务集群_第2张图片

再测试多项目

将项目打成jar包,运行.
将原项目改端口,重新运行.
当只有一个项目的时候,两个会在同一个上执行,如上图.
当两个启动时:
会进行分开进行:
springboot整合quartz实现分布式定时任务集群_第3张图片
springboot整合quartz实现分布式定时任务集群_第4张图片

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

总结

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

实际使用中的问题

当在定时任务的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);

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

你可能感兴趣的:(java,springboot,quartz)