[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上多发布几个,来进行测试,这里就不举例子了。

总结

一开始研究Quartz集群的时候,其实我是很无语的,毕竟感觉这个用处不是很大,不过研究着就会发现,有很多比自己牛多了的人,在全心全意为人民服务。

评论 35
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

盖丽男

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值