zoukankan      html  css  js  c++  java
  • spring结合Quartz的集群功能实现

    一:前沿

      在上一篇(http://www.cnblogs.com/wuhao1991/p/4331613.html)的博客中记载了定时的功能,但是集成是没有成功的,在这篇中,我在解释下这里的”集成的含义“,这里的集成是指:比如我有两个tomcat(tomcat1,tomcat2),然后现在我先启动tomcat1,在启动tomcat2,但是定时查询的功能在tomcat1上在执行,但是tomcat2上没有执行;此时我把tomcat1停止调,tomcat2又继续执行这个定时的功能;所以这里的集成说白了就是,定时的功能只能执行一个,这两个tomcat里卖弄是互斥的关系!

    二:内容技术

      在上一篇中说过,我在配置集群的时候,老是出问题,那么现在我会把这个问题记载下来;下面进行说明吧!

    application-quartz.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:aop="http://www.springframework.org/schema/aop"  
           xmlns:tx="http://www.springframework.org/schema/tx"  
           xmlns:context="http://www.springframework.org/schema/context"  
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
        	http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd  
        	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd  
        	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
        	
        	<bean id="scheduTask" class="com.xpg.chargepile.quartz.ScheduTask"></bean>    
        <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        	<property name="triggers">
        		<list>
        			<bean class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
        			 	<property name="cronExpression">
    	          			<value>0/5 * * * * ?</value>
    	        		</property>
    	        		<property name="jobDetail">
    	            		<bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    	            			<property name="targetObject" ref="scheduTask"></property>
    			    			<property name="targetMethod" value="doTask"></property>
    <!-- 			    			是否允许任务并发执行。当值为false时,表示必须等到前一个线程处理完毕后才再启一个新的线程 -->
    							<property name="concurrent" value="false"/>
    	            		</bean>
    	       			 </property>
        			</bean>
        		</list>
        	</property>
        	 <property name="dataSource">
            	<ref bean="dataSource"/>
            </property>
            <property name="applicationContextSchedulerContextKey" value="applicationContextKey"></property>
            <property name="configLocation" value="classpath:quartz.properties"></property>
        	 <property name="autoStartup" value="true" />
        </bean>
        	
    </beans>
    

     bug如下:

    严重: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
    org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.scheduling.quartz.SchedulerFactoryBean#0' defined in file [D:MyEclipsewh3.metadata.me_tcat7webappschargepileWEB-INFclassesapplicationContext-quartz.xml]: Invocation of init method failed; nested exception is org.quartz.JobPersistenceException: Couldn't store job: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean [See nested exception: java.io.NotSerializableException: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1568)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:540)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
        at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:302)
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:229)
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:298)
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:706)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:403)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:106)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4791)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5285)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:618)
        at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1100)
        at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1618)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
        at java.util.concurrent.FutureTask.run(FutureTask.java:262)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
        at java.lang.Thread.run(Thread.java:744)
    Caused by: org.quartz.JobPersistenceException: Couldn't store job: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean [See nested exception: java.io.NotSerializableException: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean]
        at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeJob(JobStoreSupport.java:1115)
        at org.quartz.impl.jdbcjobstore.JobStoreSupport$2.executeVoid(JobStoreSupport.java:1062)
        at org.quartz.impl.jdbcjobstore.JobStoreSupport$VoidTransactionCallback.execute(JobStoreSupport.java:3703)
        at org.quartz.impl.jdbcjobstore.JobStoreSupport$VoidTransactionCallback.execute(JobStoreSupport.java:3701)
        at org.quartz.impl.jdbcjobstore.JobStoreCMT.executeInLock(JobStoreCMT.java:245)
        at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeJobAndTrigger(JobStoreSupport.java:1058)
        at org.quartz.core.QuartzScheduler.scheduleJob(QuartzScheduler.java:886)
        at org.quartz.impl.StdScheduler.scheduleJob(StdScheduler.java:249)
        at org.springframework.scheduling.quartz.SchedulerAccessor.addTriggerToScheduler(SchedulerAccessor.java:308)
        at org.springframework.scheduling.quartz.SchedulerAccessor.registerJobsAndTriggers(SchedulerAccessor.java:235)
        at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:512)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1627)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1564)
        ... 25 more
    Caused by: java.io.NotSerializableException: Unable to serialize JobDataMap for insertion into database because the value of property 'methodInvoker' is not serializable: org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean
        at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.serializeJobData(StdJDBCDelegate.java:3083)
        at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.insertJobDetail(StdJDBCDelegate.java:606)
        at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeJob(JobStoreSupport.java:1112)
        ... 37 more

    使得我照这个解决方案找了好久好久啊!所以看看下面的截图(http://www.objectpartners.com/2013/07/09/configuring-quartz-2-with-spring-in-clustered-mode/)

     就是看完这句话,我才把集成给实验成功的,现在附上正确的代码<?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:aop="http://www.springframework.org/schema/aop"  
           xmlns:tx="http://www.springframework.org/schema/tx"  
           xmlns:context="http://www.springframework.org/schema/context"  
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd  
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
            
            <bean id="jobTask" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
                    <property name="jobClass" value="com.gsh.gradyate.quartz.FirstJob"/>
                      <property name="durability" value="true"/>
            </bean>
            
           <bean id="myJobTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
                <property name="jobDetail">
                    <ref bean="jobTask" />
                </property>
                <property name="cronExpression">
                    <value>1/5000 * * * * ?</value>
                </property>
        </bean>
        
         <!--  总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序  -->
        <!-- 如果lazy-init='true',则需要实例化该bean才能执行调度程序 -->
        <bean id="startQuertz" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="dataSource">
                <ref bean="dataSource"/>
            </property>
            
             <property name="schedulerContextAsMap">      
                <map>      
                    <!-- spring 管理的service需要放到这里,才能够注入成功 -->      
                    <description>schedulerContextAsMap</description>      
                    <entry key="userDao" value-ref="userDao"/>      
                </map>      
            </property>      
            
            <property name="applicationContextSchedulerContextKey" value="applicationContextKey"></property>
            <property name="configLocation" value="classpath:quartz.properties"></property>
             <property name="autoStartup" value="true" />
            <property name="triggers">
                <list>
                    <ref bean="myJobTrigger" />
                </list>
            </property>
        </bean>
    <?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:aop="http://www.springframework.org/schema/aop"  
           xmlns:tx="http://www.springframework.org/schema/tx"  
           xmlns:context="http://www.springframework.org/schema/context"  
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd  
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
            
            <bean id="scheduTask" class="com.xpg.chargepile.quartz.ScheduTask"></bean>
            
            <bean id="jobTask" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
                    <property name="jobClass" value="com.xpg.chargepile.quartz.FirstJob"/>
             
        <property name="jobDataAsMap">

                     <map>

                                  <!-- 非spring管理的service放到这里,就可以注入进去 -->
                                    <description>jobDataAsMap</description>
                                 <!-- key 属性值,value 对应的bean -->
                            <entry key="uploader" value-ref="uploader" />
                          </map>
                       </property>

            <property name="durability" value="true"/>

            </bean>
            
           <bean id="myJobTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
                <property name="jobDetail">
                    <ref bean="jobTask" />
                </property>
                <property name="cronExpression">
                    <value>1/5000 * * * * ?</value>
                </property>
        </bean>
        
         <!--  总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序  -->
        <!-- 如果lazy-init='true',则需要实例化该bean才能执行调度程序 -->
        <bean id="startQuertz" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="dataSource">
                <ref bean="dataSource"/>
            </property>
            
             <property name="schedulerContextAsMap">      
                <map>      
                    <!-- spring 管理的service需要放到这里,才能够注入成功 -->      
                    <description>schedulerContextAsMap</description>      
                    <entry key="userDao" value-ref="userDao"/>      
                </map>      
            </property>      
            
            <property name="applicationContextSchedulerContextKey" value="applicationContextKey"></property>
            <property name="configLocation" value="classpath:quartz.properties"></property>
             <property name="autoStartup" value="true" />
            <property name="triggers">
                <list>
                    <ref bean="myJobTrigger" />
                </list>
            </property>
        </bean>

    firstjob.java:

    package com.gsh.graduate.quartz;
    
    import java.util.Date;
    
    import org.quartz.JobExecutionContext;
    import org.quartz.SchedulerContext;
    import org.quartz.SchedulerException;
    import org.springframework.beans.factory.config.BeanDefinition;
    import org.springframework.context.annotation.Scope;
    import org.springframework.scheduling.quartz.QuartzJobBean;
    import org.springframework.stereotype.Component;
    
    import com.gsh.graduate.dao.UserDao;
    import com.gsh.graduate.pojo.User;
    @Component
    @Scope(value = BeanDefinition.SCOPE_PROTOTYPE)
    public class FirstJob extends QuartzJobBean {

    // @AutoWire
     // private UserDao userDao
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
                this.userDao = userDao;
            }
    
            @Override
            protected void executeInternal(JobExecutionContext context) {                  
                //获取JobExecutionContext中的service对象    
                try {
                    SchedulerContext skedCtx = context.getScheduler().getContext();
                    userDao=(UserDao) skedCtx.get("userDao");
                } catch (SchedulerException e) {
                    e.printStackTrace();
                }      
                User u=userDao.getUserByID("12345");
                System.out.println("---"+u);
                System.out.println("定时开始0,1,2,3");
                System.out.println(new Date());
                System.out.println("定时结束,game over");
            }
    }

    特别说明:这里面的对象必须在配置文件里面声明,在firstjob.java类中,如果你想通过这样像代码中注释的那样,自动注入会报一下错误;所以可以看下spring 通过配置向quartz 注入service(http://blog.csdn.net/whaosy/article/details/6298686)

    2015-03-12 14:47:20 ERROR org.quartz.core.JobRunShell.run(211) | Job DEFAULT.jobTask threw an unhandled Exception: 
    java.lang.NullPointerException
        at com.gsh.graduate.quartz.FirstJob.executeInternal(FirstJob.java:53)
        at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
    2015-03-12 14:47:20 ERROR org.quartz.core.ErrorLogger.schedulerError(2425) | Job (DEFAULT.jobTask threw an exception.
    org.quartz.SchedulerException: Job threw an unhandled exception. [See nested exception: java.lang.NullPointerException]
        at org.quartz.core.JobRunShell.run(JobRunShell.java:213)
        at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
    Caused by: java.lang.NullPointerException
        at com.gsh.graduate.quartz.FirstJob.executeInternal(FirstJob.java:53)
        at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75)
        at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
        ... 1 more

    上面第一次实验的那种bug本来有两种配置方式的,但是我在配置好了之后,实验以前的没有报bug,我都郁闷了,附加代码看看

    <?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:aop="http://www.springframework.org/schema/aop"  
           xmlns:tx="http://www.springframework.org/schema/tx"  
           xmlns:context="http://www.springframework.org/schema/context"  
           xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd  
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd  
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd  
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
            
            <!---方案一->
            <bean id="scheduTask" class="com.gsh.graduate.quartz.ScheduTask"></bean>
            
    <!--         调用的对象和方法的指定 -->
            <bean id="jobTask" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
    <!--         <bean id="jobTask" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> -->
    <!--                 <property name="jobClass" value="com.gsh.graduate.quartz.FirstJob"/> -->
    <!--                   <property name="durability" value="true"/> -->
    <!--                 是否允许任务并发执行。当值为false时,表示必须等到前一个线程处理完毕后才再启一个新的线程 -->
                    <property name="concurrent" value="false"/>
                    <property name="targetObject" ref="scheduTask"></property>
                    <property name="targetMethod" value="doTask"></property>
            </bean>
            
           <bean id="myJobTrigger"  class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
                <property name="jobDetail">
                    <ref bean="jobTask" />
                </property>
                <property name="cronExpression">
                    <value>1/5000 * * * * ?</value>
                </property>
        </bean>
        
         <!--  总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序  -->
        <!-- 如果lazy-init='true',则需要实例化该bean才能执行调度程序 -->
    <!--     <bean id="startQuertz" lazy-init="false" autowire="no" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> -->
        <bean id="startQuertz" lazy-init="false" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="dataSource">
                <ref bean="dataSource"/>
            </property>
            
             <property name="schedulerContextAsMap">      
                <map>      
                    <!-- spring 管理的service需要放到这里,才能够注入成功 -->      
                    <description>schedulerContextAsMap</description>      
                    <entry key="userDao" value-ref="userDao"/>      
                </map>      
            </property>      
            <property name="applicationContextSchedulerContextKey" value="applicationContextKey"></property>
            <property name="configLocation" value="classpath:quartz.properties"></property>
             <property name="autoStartup" value="true" />
            <property name="triggers">
                <list>
                    <ref bean="myJobTrigger" />
                </list>
            </property>
        </bean>
            
    <!--方案2-->
       <!--  <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
            <property name="triggers">
                <list>
                    <bean class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
                         <property name="cronExpression">
                              <value>0/5 * * * * ?</value>
                        </property>
                        <property name="jobDetail">
                            <bean class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
                                <property name="targetObject" ref="scheduTask"></property>
                                <property name="targetMethod" value="doTask"></property>
                                是否允许任务并发执行。当值为false时,表示必须等到前一个线程处理完毕后才再启一个新的线程
                                <property name="concurrent" value="false"/>
                            </bean>
                            </property>
                    </bean>
                </list>
            </property>
             <property name="dataSource">
                <ref bean="dataSource"/>
            </property>
            <property name="applicationContextSchedulerContextKey" value="applicationContextKey"></property>
            <property name="configLocation" value="classpath:quartz.properties"></property>
             <property name="autoStartup" value="true" />
        </bean> -->
            
    </beans>
    这是所有的代码,两种方案

    三:总结,折腾了这么久终于把集成给折腾成功了啊,这是接触新鲜的东西,就是不一样啊,解决问题的能力还是有涨进的啊!继续Go!Boy,今天一下在把有关Quartz的都写了!不枉我研究了两天啊!

  • 相关阅读:
    Spark2 Dataset DataFrame空值null,NaN判断和处理
    Spark2 文件处理和jar包执行
    &与&&, |与||区别
    Scala实现乘法口诀
    Hive desc
    Hive FUNCTIONS函数
    Hive show
    MySQL行列转换拼接
    MySQL字符串连接
    SQLServer之索引简介
  • 原文地址:https://www.cnblogs.com/wuhao1991/p/4332446.html
Copyright © 2011-2022 走看看