Quartz是一个开源的作业调度框架,它完全由Java写成,并设计用于J2SE和J2EE应用中。它提供了巨大的灵活性而不牺牲简单性。你能够用它来为执行一个作业而创建简单的或复杂的调度,简单的说就是可以实现java的定时任务。

一、问题描述

  但是,当在集群环境下,每一台服务器上都有这段定时发送信息的代码,多个服务器下如何用quartz协调处理自动化JOB。

  如果现在有A,B,C三台机器同时作为集群服务器对外统一提供服务:

  A、B、C三台机器上各有一个QUARTZ,他们会按照即定的SCHEDULE自动执行各自的任务。这样的架构其实有点像多线程,可能产生脏读,脏写。因为三台APP SERVER里都有QUARTZ,因此会存在重复处理TASK的现象。

  一般有三种解决方案:

  1.一般外面的解决方案是只在一台 APP 上装 QUARTZ,其它两台不装,这样集群就形同虚设了;

  2.另一种解决方案是动代码,这样就要影响到原来已经写好的QUARTZ JOB的代码了,这对程序开发人员来说比较痛苦;

  3.quartz自身提供了解决集群环境下配置的接口,通过重写类并进行配置即可。

  下面,就详细介绍一下quartz在集群环境下如何配置。

二、quartz在集群下的配置

1.首先在quartz官网上下载相应的jar包。我下载的是quartz1-1.5.2.zip。

2.解压后在docs\dbTables目录下找到相应的数据库创建表的sql语句,并在数据库中执行该sql语句,执行后会创建十二张表。这里我使用的是mysql数据库,所以用的是tables_mysql.sql文件。

3.导入jar包quartz-all-1.5.2.jar,并Build Path。

注意:spring3.0不支持quartz2.0以上的版本,且quartz1.6.0版本有些问题,最好不要使用。

4.因为quartz在集群下配置依赖于将节点信息存放到数据库中,而org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean不支持序列化,不能将信息存放到数据库中,所以需要重写QuartzJobBean类。

import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.quartz.QuartzJobBean; public class MyDetailQuartzJobBean extends QuartzJobBean {
protected final Log logger = LogFactory.getLog(getClass());
private String targetObject;
private String targetMethod;
private ApplicationContext ctx; @Override
protected void executeInternal(JobExecutionContext context)
throws JobExecutionException {
try {
logger.info("execute [" + targetObject + "] at once>>>>>>");
Object otargetObject = ctx.getBean(targetObject);
Method m = null; try {
m = otargetObject.getClass().getMethod(targetMethod, new Class[] {JobExecutionContext.class});
m.invoke(otargetObject, new Object[] {context});
} catch (SecurityException e) {
logger.error(e);
} catch (NoSuchMethodException e) {
logger.error(e);
}
} catch (Exception e) {
throw new JobExecutionException(e);
}
} public void setApplicationContext(ApplicationContext applicationContext) {
this.ctx = applicationContext;
} public void setTargetObject(String targetObject) {
this.targetObject = targetObject;
} public void setTargetMethod(String targetMethod) {
this.targetMethod = targetMethod;
}
}

5.编写要定时执行的代码,详见StudentTimer.java。

import java.util.Date;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Service; @Service
public class StudentTimer implements Job { @Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println(new Date()+"Student中的execute正在执行...");
} }

注意:如果没有实现Job接口,则方法参数必须为JobExecutionContext arg0,如下:

import java.util.Date;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Service; @Service
public class StudentTimer { public void update(JobExecutionContext arg0) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println(new Date()+"Student中的update正在执行...");
} }

6.在application-context.xml中进行配置,详见timerTask.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:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd"
> <bean id="doJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>com.core.Util.MyDetailQuartzJobBean</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="targetObject" value="studentTimer" />
<entry key="targetMethod" value="execute" />
</map>
</property>
</bean>
<!-- 触发器的bean的设置,在这里我们设置了我们要触发的jobDetail是哪个。这里我们定义了要触发的jobDetail是searchEngerneTask,即触发器去触发哪个bean..并且我们还定义了触发的时间 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="doJob" />
</property>
<property name="cronExpression">
<!-- 关键在配置此表达式,时间设置这里表示20秒触发一次,具体可以自己去找资料看 -->
<value>0/20 * * * * ?</value>
</property>
</bean>
<!-- 管理触发器的总设置,管理我们的触发器列表,可以在bean的list中放置多个触发器。 -->
<bean autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
</list>
</property>
<property name="applicationContextSchedulerContextKey" value="applicationContext" />
<property name="configLocation" value="classpath:com/core/Config/quartz.properties" />
</bean>
</beans>

7.编写quartz.properties文件。

#==============================================================
#Configure Main Scheduler Properties
#==============================================================
org.quartz.scheduler.instanceName = quartzScheduler
org.quartz.scheduler.instanceId = AUTO
#org.quartz.scheduler.wrapJobExecutionInUserTransaction = true
#==============================================================
#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 =
org.quartz.jobStore.dataSource = myDS #==============================================================
#Configure DataSource
#==============================================================
org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver
org.quartz.dataSource.myDS.URL = jdbc\:mysql\://localhost\:/quartz?useUnicode\=true&amp;characterEncoding\=UTF-
org.quartz.dataSource.myDS.user = root
org.quartz.dataSource.myDS.password =
org.quartz.dataSource.myDS.maxConnections =
#org.quartz.dataSource.myDS.connectionProvider.class = org.quartz.utils.PoolingConnectionProvider #==============================================================
#Configure ThreadPool
#==============================================================
org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount =
org.quartz.threadPool.threadPriority =
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread =true

如何解决quartz在集群下出现的资源抢夺现象的更多相关文章

  1. quartz在集群环境下的最终解决方案

    在集群环境下,大家会碰到一直困扰的问题,即多个 APP 下如何用 quartz 协调处理自动化 JOB . 大家想象一下,现在有 A , B , C3 台机器同时作为集群服务器对外统一提供 SERVI ...

  2. 序列化人人网框架下的DAO?也就是在Spring下序列化DAO的问题(spring+quartz集群下)

    人人网框架地址:http://code.google.com/p/paoding-rose/ 问题发生: 用Quartz作集群时用JobDataMap传递DAO,提示DAO未序列化,可框架的DAO为接 ...

  3. 【淘淘】Quartz之集群利弊

    一.前言: 虽然单个Quartz实例能给予我们很好的任务job调度能力,但它不能满足典型的企业需求,如可伸缩性.高可靠性满足.假如你需要故障转移的能力并能运行日益增多的 Job,Quartz集群势必成 ...

  4. Java应用集群下的定时任务处理方案(mysql)

    Java应用集群下的定时任务处理方案(mysql)   因为自己有csdn和博客园两个博客, 所以两边都会发一下. csdn地址: http://blog.csdn.net/u012881584/ar ...

  5. Spring Boot Quartz 分布式集群任务调度实现

    Spring Boot Quartz 主要内容 Spring Scheduler 框架 Quartz 框架,功能强大,配置灵活 Quartz 集群 mysql 持久化定时任务脚本(tables_mys ...

  6. 定时组件quartz系列<二>quartz的集群原理

    1.基本信息:      Quartz是一个开源的作业调度框架,它完全由java写成,并设计用于J2Se和J2EE应用中.它提供了巨大的灵活性而不牺牲简单性.你能够用它 来为执行一个作业而创建简单的或 ...

  7. 浅析Quartz的集群配置

    浅析Quartz的集群配置(一) 收藏人:Rozdy     2015-01-13 | 阅:1  转:22    |   来源   |  分享               1 基本信息 摘要:Quar ...

  8. Redis集群下过期key监听

    1. 前言 在使用redis集群时,发现过期key始终监听不到.网上也没有现成的解决方案.于是想,既然不能监听集群,那我可以建立多个redis连接,分别对每个redis的key过期进行监听.以上做法可 ...

  9. 解决应用服务器变为集群后的Session问题

    2.2.4.2 解决应用服务器变为集群后的Session问题 先来看一下什么是Session. 用户使用网站的服务,基本上需要浏览器与Web 服务器的多次交互.HTTP 协议本身是无状态的,需要基于H ...

随机推荐

  1. org.apache.jasper.JasperException: #{...} is not allowed in template

    org.apache.jasper.JasperException: #{...} is not allowed in template   针对jsp页面使用JQueryUI元素,出现org.apa ...

  2. 2017.11.10 MPLAB IPE + ICD-3+ PIC32MM

    A trouble with ICD-3  programmer. MCU:  PIC32MM sw:  MPLAB IPE tool:  ICD-3 1 product introduction a ...

  3. 用 hash 找出指定一个数, 这个数是数组两个值的总和, 找出两个值的坐标

    var twoSum = function(nums, target) { var len = nums.length; var exist = {} //这里利用了hash来存放已知的 exist[ ...

  4. ubuntu android 开始git安装

    ubuntu android 开始git安装   git安装: http://source.android.com/source/initializing.html网站提示到以下网址下载: http: ...

  5. CABAC与CAVLC有什么区别?

    待完善 7.3.12 用 CAVLC 方式编码的残差数据的语义 coeff_token   指明了非零系数的个数,拖尾系数的个数. trailing_ones_sign_flag 拖尾系数的符号 - ...

  6. C++ Primer 第四版中文版

    C++Primer是C++的经典教程. 开始时间:2014-08-10 完成时间:2014-08-28 学习成果:基础语法+

  7. yield 与生成器

    yield的功能类似于return,但是不同之处在于它返回的是生成器. 生成器 生成器是通过一个或多个yield表达式构成的函数,每一个生成器都是一个迭代器(但是迭代器不一定是生成器). 如果一个函数 ...

  8. CentOS系统内核、操作系统位数以及系统参数查看

    2016-07-29 一.系统内核的查看方法 1.uname -a 显示详细的内核信息 Linux localhost.localdomain 3.10.0-229.el7.x86_64 #1 SMP ...

  9. LeetCode Minimum Time Difference

    原题链接在这里:https://leetcode.com/problems/minimum-time-difference/description/ 题目: Given a list of 24-ho ...

  10. 洛谷 1155 (NOIp2008)双栈排序——仔细分析不合法的条件

    题目:https://www.luogu.org/problemnew/show/P1155 这道题教会我们要多思考. 好好分析过后发现同一个栈里不能有升序.就用它写了一个30分. #include& ...