springboot-quartz整合

springboot整合quartz集群

quartz官网

背景

同一份具有定时任务功能(定时发送消息)的代码需要部署到两台或以上的服务器上,同一定时任务只需要在多台的服务运行,避免重复的操作(重复发送)。

quartz集群

参考:http://blog.csdn.net/wenniuwuren/article/details/45866807

Quartz的集群是在同一个数据库下, 由数据库的数据来确定调度任务是否正在执行, 正在执行则其他服务器就不能去执行该行调度数据。 这个跟很多项目是用Zookeeper做集群不一样, 这些项目是靠Zookeeper选举出来的的服务器去执行, 可以理解为Quartz靠数据库选举一个服务器来执行。

整合说明

关键依赖

<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.3.0</version>
</dependency>

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>4.3.12.RELEASE</version>
</dependency>

工厂类

SpringJobFactory:该任务工厂类可以使具体的Job交给spring来管理,因此我们可以在Job类上注入我们需要的业务级别的代码(service类)

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

/**
 * 此类使quart的job能够使用@Autowired spring管理的bean
 *
 * @author samlen_tsoi
 * @date 2017/11/28
 */
@Component
public class SpringJobFactory extends AdaptableJobFactory {

    @Autowired
    private AutowireCapableBeanFactory capableBeanFactory;

    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        capableBeanFactory.autowireBean(jobInstance);
        return jobInstance;
    }

}

SchedulerConfig:向spring注册SchedulerFactoryBean

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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 java.io.IOException;
import java.util.Properties;

/**
 * @author samlen_tsoi
 */
@Slf4j
@Configuration
@SuppressWarnings("ALL")
public class SchedulerConfig {

    @Bean
    public Properties properties() throws IOException {
        Properties prop = new Properties();
        prop.load(new ClassPathResource("/quartz.properties").getInputStream());
        return prop;
    }

    @Autowired
    private SpringJobFactory springJobFactory;

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
        //是否覆盖就任务
        schedulerFactoryBean.setOverwriteExistingJobs(true);
        //延迟多久启动
        schedulerFactoryBean.setStartupDelay(10);
        //设置基本的配置
        schedulerFactoryBean.setQuartzProperties(properties());
        //是否自动启动
        schedulerFactoryBean.setAutoStartup(Boolean.TRUE);
        //必须设置,具体的任务实例才能交给spring管理
        schedulerFactoryBean.setJobFactory(springJobFactory);
        return schedulerFactoryBean;
    }
}

quartz.properties

#============================================================================
# Configure Main Scheduler Properties
#============================================================================
# 属性可为任何值,用在 JDBC JobStore 中来唯一标识实例,但是所有集群节点中必须相同
org.quartz.scheduler.instanceName = MyClusteredScheduler
# 属性为 AUTO即可,基于主机名和时间戳来产生实例 ID
org.quartz.scheduler.instanceId = AUTO
org.quartz.scheduler.makeSchedulerThreadDaemon = true
# 是否使用自己的配置文件
org.quartz.jobStore.useProperties=true


#============================================================================
# Configure ThreadPool
#============================================================================
# 线程池的实现类
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
# 是否为守护线程
org.quartz.threadPool.makeThreadsDaemons = true
# 线程数
org.quartz.threadPool.threadCount = 25
# 线程的优先级
org.quartz.threadPool.threadPriority = 5

#============================================================================
# Configure JobStore
#============================================================================
# 属性为 JobStoreTX,将任务持久化到数据中。因为集群中节点依赖于数据库来传播 Scheduler 实例的状态,你只能在使用 JDBC JobStore 时应用 Quartz 集群,这意味着你必须使用 JobStoreTX 或是 JobStoreCMT 作为 Job 存储;你不能在集群中使用 RAMJobStore。
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
# 数据库中quartz表的表名前缀
org.quartz.jobStore.tablePrefix = qrtz_
# 属性为 true,你就告诉了 Scheduler 实例要它参与到一个集群当中。这一属性会贯穿于调度框架的始终,用于修改集群环境中操作的默认行为。
org.quartz.jobStore.isClustered = true
org.quartz.jobStore.dataSource = myDs
org.quartz.jobStore.misfireThreshold = 60000
# 属性定义了Scheduler 实例检入到数据库中的频率(单位:毫秒)。Scheduler 检查是否其他的实例到了它们应当检入的时候未检入;这能指出一个失败的 Scheduler 实例,且当前 Scheduler 会以此来接管任何执行失败并可恢复的 Job。通过检入操作,Scheduler 也会更新自身的状态记录。clusterChedkinInterval 越小,Scheduler 节点检查失败的 Scheduler 实例就越频繁。默认值是 15000 (即15 秒)。
org.quartz.jobStore.clusterCheckinInterval = 5000


#============================================================================
# Configure Datasources  
#============================================================================
org.quartz.dataSource.myDs.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDs.URL = jdbc:mysql://localhost:3306/sbquartz?characterEncoding=utf8&useSSL=false
org.quartz.dataSource.myDs.user = root
org.quartz.dataSource.myDs.password = root
org.quartz.dataSource.myDs.maxConnections = 5
org.quartz.dataSource.myDs.validationQuery = select 1

其他关键类

samlen.tsoi.sbquartz.web.helper.SchedulerHelper: 提供了一下方法:

  • createScheduler: 创建并开启任务

  • deleteScheduler: 关闭并删除任务

  • updateScheduler: 更新任务

samlen.tsoi.sbquartz.entity.JobConfig: 用于组装任务详情

  • id: 任务ID

  • JobClass: 任务的具体类名

  • groupName: 任务的组名

  • cronTime: 定时触发时间

  • jobData: 一个map,存放额外的数据

测试

  • 建库建表,插数据,相关sql见db目录

  • 依次启动samlen.tsoi.sbquartz.web.WebApplicationFirst,samlen.tsoi.sbquartz.web.WebApplicationSecond

  • 使用postman之类工具访问samlen.tsoi.sbquartz.web.WebApplicationFirst.JobControllerrestApi,观察控制台打印的日志

github地址

参考博文

  • http://blog.csdn.net/wenniuwuren/article/details/45866807

  • http://blog.csdn.net/musuny/article/details/75808044

  • http://blog.csdn.net/lisi1129/article/details/76121057

  • http://tzz6.iteye.com/blog/2210485

  • http://blog.csdn.net/growing_duck/article/details/75115913

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,834评论 25 707
  • 在此特此声明:一下所有链接均来自互联网,在此记录下我的查阅学习历程,感谢各位原创作者的无私奉献 ! 技术一点一点积...
    远航的移动开发历程阅读 11,092评论 12 197
  • 未来的生活谁也不清楚,不知道以后会过怎样的日子,我唯一能够把握的也只有现在,抓住当下的每一个机会,慢慢地成就自己。
    智青阅读 225评论 0 0
  • 人到中年的我们生活重心已经全然放在了孩子的身上,无需刻意的偏移,而是一种自然而然的心理倾向! 无...
    唯美儿阅读 332评论 0 3
  • 人不能缺少的是感恩的心。 我是一个普通的上班族,在马上40年的人生中需要感恩的又何止五件事。 第一 感恩我有一个双...
    闲看庭前花开阅读 396评论 1 1