[java]spring-Quartz集群

本文涉及的产品
云数据库 RDS MySQL Serverless,0.5-2RCU 50GB
云数据库 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上多发布几个,来进行测试,这里就不举例子了。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
目录
相关文章
|
13天前
|
人工智能 Java API
Spring AI 抢先体验,5 分钟玩转 Java AI 应用开发
Spring Cloud Alibaba AI 以 Spring AI 为基础,并在此基础上提供阿里云通义系列大模型全面适配,让用户在 5 分钟内开发基于通义大模型的 Java AI 应用。
|
2天前
|
移动开发 前端开发 NoSQL
ruoyi-nbcio从spring2.7.18升级springboot到3.1.7,java从java8升级到17(二)
ruoyi-nbcio从spring2.7.18升级springboot到3.1.7,java从java8升级到17(二)
12 0
|
2天前
|
JSON 前端开发 Java
【JAVA进阶篇教学】第七篇:Spring中常用注解
【JAVA进阶篇教学】第七篇:Spring中常用注解
|
2天前
|
XML Java 数据库连接
【JAVA基础篇教学】第十五篇:Java中Spring详解说明
【JAVA基础篇教学】第十五篇:Java中Spring详解说明
|
4天前
|
前端开发 安全 Java
使用Spring框架加速Java开发
使用Spring框架加速Java开发
10 0
|
6天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
47 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
11天前
|
XML 监控 安全
18:面向切面编程-Java Spring
18:面向切面编程-Java Spring
27 5
|
11天前
|
缓存 NoSQL Java
17:缓存机制-Java Spring
17:缓存机制-Java Spring
23 5
|
11天前
|
Java 数据库连接 数据库
16:事务-Java Spring
16:事务-Java Spring
26 5
|
11天前
|
SQL Java 数据库连接
15:MyBatis对象关系与映射结构-Java Spring
15:MyBatis对象关系与映射结构-Java Spring
30 4