• 如何解决quartz在集群下出现的资源抢夺现象


      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.解压后在docsdbTables目录下找到相应的数据库创建表的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 = 20000    
    org.quartz.jobStore.dataSource = myDS  
       
    #==============================================================    
    #Configure DataSource    
    #==============================================================   
    org.quartz.dataSource.myDS.driver = com.mysql.jdbc.Driver  
    org.quartz.dataSource.myDS.URL = jdbc:mysql://localhost:3306/quartz?useUnicode=true&amp;characterEncoding=UTF-8  
    org.quartz.dataSource.myDS.user = root  
    org.quartz.dataSource.myDS.password = 123 
    org.quartz.dataSource.myDS.maxConnections = 30 
    #org.quartz.dataSource.myDS.connectionProvider.class = org.quartz.utils.PoolingConnectionProvider 
      
    #==============================================================    
    #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 
  • 相关阅读:
    networkX用法整
    在人生路上对我影响最大的三位老师
    介绍自己
    介绍自己
    自我介绍
    打印沙漏1
    介绍自己
    对我影响最大的三位老师
    人生路上影响对我最大的三位老师
    1.自我介绍
  • 原文地址:https://www.cnblogs.com/zlbx/p/5139562.html
Copyright © 2020-2023  润新知