[java]spring-Quartz集群

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: [java]spring-Quartz集群

上篇博客讲了quartz的用法,解决了定时任务的问题,但是当我们搭建集群,将服务部署在多个机器上时,很有可能引起冲突的问题,一个任务,多次执行,那么如何解决这个问题呢,quartz提供了集群的搭建方案,确保一个任务,只会在一个时间执行一次,下面我们来学习一下quartz集群的搭建。


原理


quartz连接数据库,然后从表里去读取相关配置信息,多个任务通过表来达到统一。


搭建


环境


spring 4.0.6


quartz 2.2.3


mysql 5.1.38


druid 1.1.0


首先来看一下目录结构:



pom文件引用如下:


<?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>
    <groupId>com.spring.quartzm</groupId>
    <artifactId>quartzm</artifactId>
    <version>1.0-SNAPSHOT</version>
    <properties>
        <springframework.version>4.0.6.RELEASE</springframework.version>
        <quartz.version>2.2.3</quartz.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <!-- spring-tx包必须导入,因为Quartz需要依赖该包 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${springframework.version}</version>
        </dependency>
        <!-- Quartz framework -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>${quartz.version}</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.0</version>
        </dependency>
    </dependencies>
</project>


数据库连接


数据库的建表语句等在quartz-2.2.3-distribution.tar.gz包里面quartz-2.2.3-distribution.tar\quartz-2.2.3\docs\dbTables\下,因为我的数据库是mysql,所以我选择的是tables_mysql_innodb.sql


spring我只用了一个配置文件,名字为quartz-context.xml,数据库建好以后,配置数据库连接,如下:


  <!--数据库连接设置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="${itoo_jdbc_url}"/>
        <property name="username" value="${itoo_jdbc_username}"/>
        <property name="password" value="${itoo_jdbc_password}"/>
    </bean>
    <!--<import resource="classpath:quartz-db.properties"/>-->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="1" />
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="locations">
            <list>
                <value>classpath:db.properties</value>
                <!--<value>classpath:dubbo-server.properties</value>-->
            </list>
        </property>
    </bean>


quartz配置文件


配置文件内容为:


#==============================================================
#Configure Main Scheduler Properties
#==============================================================
org.quartz.scheduler.instanceName = defaultScheduler  
org.quartz.scheduler.instanceId = AUTO  
#==============================================================
#Configure JobStore
#==============================================================
org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX  
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate  
org.quartz.jobStore.tablePrefix = QRTZ_  
org.quartz.jobStore.isClustered = true  
org.quartz.jobStore.clusterCheckinInterval = 20000    
org.quartz.jobStore.dataSource = myDS  
org.quartz.jobStore.maxMisfiresToHandleAtATime = 1  
org.quartz.jobStore.misfireThreshold = 120000  
org.quartz.jobStore.txIsolationLevelSerializable = true  
#==============================================================
#Configure ThreadPool
#==============================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool  
org.quartz.threadPool.threadCount = 10  
org.quartz.threadPool.threadPriority = 5  
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true  
#==============================================================
#Skip Check Update
#update:true
#not update:false
#==============================================================
org.quartz.scheduler.skipUpdateCheck = true   
#============================================================================
# Configure Plugins
#============================================================================
org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin     
org.quartz.plugin.shutdownhook.class = org.quartz.plugins.management.ShutdownHookPlugin  
org.quartz.plugin.shutdownhook.cleanShutdown = true  


spring配置文件内容


JobDetail配置


上篇博客中我们配置jobDetail时使用的是org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean

但是在搭建集群时使用这个会报错,说我们的任务类没有序列化,所以我们使用另一种

org.springframework.scheduling.quartz.JobDetailFactoryBean


如下:


    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.cdsmartlink.service.impl.ExtendsJob"/>
        <property name="durability" value="true"/>
        <property name="requestsRecovery" value="true"/>
    </bean>


Trigger与上一篇相同即可


<!-- 创建SimpleTrigger触发器 -->
    <bean class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean" id="simpleTrigger">
        <!-- 引用任务 -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 指定循环时间,以秒为单位 -->
        <property name="repeatInterval" value="10000"/>
    </bean>
    <!-- 创建CronTrigger触发器 -->
    <bean class="org.springframework.scheduling.quartz.CronTriggerFactoryBean" id="cronTrigger">
        <!-- 引用任务 -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 指定Cron表达式 -->
        <property name="cronExpression" value="*/5 * * * * ?"/>
    </bean>


Scheduling需要注意一下


<!-- 创建调度器 -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" id="stdScheduler">
        <property name="dataSource" ref="dataSource"></property>
        <!--可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 -->
        <property name="overwriteExistingJobs" value="true" />
        <!--必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动 -->
        <property name="startupDelay" value="30" />
        <!-- 设置自动启动 -->
        <property name="autoStartup" value="true" />
        <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
        <property name="configLocation" value="classpath:quartz.properties" />
        <property name="triggers">
            <list>
                <ref bean="cronTrigger"/>
        </list>
    </property>
</bean>


完整的quartz-context.xml


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    <context:component-scan base-package="com.cdsmartlink.*" />
    <!--&lt;!&ndash; 创建任务 &ndash;&gt;-->
    <!--<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" id="jobDetail">-->
        <!--&lt;!&ndash; 目标对象 &ndash;&gt;-->
        <!--<property name="targetObject" ref="myJob"/>-->
        <!--&lt;!&ndash; 目标方法 &ndash;&gt;-->
        <!--<property name="targetMethod" value="execute"/>-->
        <!--&lt;!&ndash;concurrent:false表示上一个任务执行完后再开启新的任务&ndash;&gt;-->
        <!--<property name="concurrent" value="false"/>-->
    <!--</bean>-->
    <bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
        <property name="jobClass" value="com.cdsmartlink.service.impl.ExtendsJob"/>
        <property name="durability" value="true"/>
        <property name="requestsRecovery" value="true"/>
    </bean>
    <!-- 创建SimpleTrigger触发器 -->
    <bean class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean" id="simpleTrigger">
        <!-- 引用任务 -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 指定循环时间,以秒为单位 -->
        <property name="repeatInterval" value="10000"/>
    </bean>
    <!-- 创建CronTrigger触发器 -->
    <bean class="org.springframework.scheduling.quartz.CronTriggerFactoryBean" id="cronTrigger">
        <!-- 引用任务 -->
        <property name="jobDetail" ref="jobDetail"/>
        <!-- 指定Cron表达式 -->
        <property name="cronExpression" value="*/5 * * * * ?"/>
    </bean>
    <!-- 创建调度器 -->
    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean" id="stdScheduler">
        <property name="dataSource" ref="dataSource"></property>
        <!--可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了 -->
        <property name="overwriteExistingJobs" value="true" />
        <!--必须的,QuartzScheduler 延时启动,应用启动完后 QuartzScheduler 再启动 -->
        <property name="startupDelay" value="30" />
        <!-- 设置自动启动 -->
        <property name="autoStartup" value="true" />
        <property name="applicationContextSchedulerContextKey" value="applicationContextKey" />
        <property name="configLocation" value="classpath:quartz.properties" />
        <property name="triggers">
            <list>
                <ref bean="cronTrigger"/>
            </list>
        </property>
    </bean>
    <!--数据库连接设置-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close">
        <property name="url" value="${itoo_jdbc_url}"/>
        <property name="username" value="${itoo_jdbc_username}"/>
        <property name="password" value="${itoo_jdbc_password}"/>
    </bean>
    <!--<import resource="classpath:quartz-db.properties"/>-->
    <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
        <property name="order" value="1" />
        <property name="ignoreUnresolvablePlaceholders" value="true" />
        <property name="locations">
            <list>
                <value>classpath:db.properties</value>
                <!--<value>classpath:dubbo-server.properties</value>-->
            </list>
        </property>
    </bean>
</beans>


任务类


任务类需要实现Job接口


package com.cdsmartlink.service;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
/**
 * Created by L on 2017-07-22.
 */
@Component
public class ExtendsJob implements Job{
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        System.out.println("这里是我们的任务代码!!!!");
    }
}


测试


package com.cdsmartlink.service.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Created by L on 2017-07-22.
 */
public class MyJobTest{
    @Test
    public void test() throws InterruptedException {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("quartz-context.xml");
        Thread.sleep(60000);
    }
}


其实也可以在tomcat上多发布几个,来进行测试,这里就不举例子了。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
1月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
71 2
|
19天前
|
Java 开发者 微服务
Spring Boot 入门:简化 Java Web 开发的强大工具
Spring Boot 是一个开源的 Java 基础框架,用于创建独立、生产级别的基于Spring框架的应用程序。它旨在简化Spring应用的初始搭建以及开发过程。
38 6
Spring Boot 入门:简化 Java Web 开发的强大工具
|
1月前
|
人工智能 前端开发 Java
基于开源框架Spring AI Alibaba快速构建Java应用
本文旨在帮助开发者快速掌握并应用 Spring AI Alibaba,提升基于 Java 的大模型应用开发效率和安全性。
基于开源框架Spring AI Alibaba快速构建Java应用
|
2月前
|
前端开发 Java 数据库连接
Spring 框架:Java 开发者的春天
Spring 框架是一个功能强大的开源框架,主要用于简化 Java 企业级应用的开发,由被称为“Spring 之父”的 Rod Johnson 于 2002 年提出并创立,并由Pivotal团队维护。
77 1
Spring 框架:Java 开发者的春天
|
2月前
|
分布式计算 大数据 Java
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
39 1
大数据-86 Spark 集群 WordCount 用 Scala & Java 调用Spark 编译并打包上传运行 梦开始的地方
|
2月前
|
Java 数据库连接 开发者
Spring 框架:Java 开发者的春天
【10月更文挑战第27天】Spring 框架由 Rod Johnson 在 2002 年创建,旨在解决 Java 企业级开发中的复杂性问题。它通过控制反转(IOC)和面向切面的编程(AOP)等核心机制,提供了轻量级的容器和丰富的功能,支持 Web 开发、数据访问等领域,显著提高了开发效率和应用的可维护性。Spring 拥有强大的社区支持和丰富的生态系统,是 Java 开发不可或缺的工具。
|
2月前
|
JSON Java Maven
实现Java Spring Boot FCM推送教程
本指南介绍了如何在Spring Boot项目中集成Firebase云消息服务(FCM),包括创建项目、添加依赖、配置服务账户密钥、编写推送服务类以及发送消息等步骤,帮助开发者快速实现推送通知功能。
109 2
|
1月前
|
Java 数据库连接 API
Spring 框架的介绍(Java EE 学习笔记02)
Spring是一个由Rod Johnson开发的轻量级Java SE/EE一站式开源框架,旨在解决Java EE应用中的多种问题。它采用非侵入式设计,通过IoC和AOP技术简化了Java应用的开发流程,降低了组件间的耦合度,支持事务管理和多种框架的无缝集成,极大提升了开发效率和代码质量。Spring 5引入了响应式编程等新特性,进一步增强了框架的功能性和灵活性。
45 0
|
2月前
|
存储 人工智能 Java
将 Spring AI 与 LLM 结合使用以生成 Java 测试
AIDocumentLibraryChat 项目通过 GitHub URL 为指定的 Java 类生成测试代码,支持 granite-code 和 deepseek-coder-v2 模型。项目包括控制器、服务和配置,能处理源代码解析、依赖加载及测试代码生成,旨在评估 LLM 对开发测试的支持能力。
50 1
|
2月前
|
Java BI 调度
Java Spring的定时任务的配置和使用
遵循上述步骤,你就可以在Spring应用中轻松地配置和使用定时任务,满足各种定时处理需求。
158 1
下一篇
DataWorks