spring結合Quartz的集羣功能實現

一:前沿html

  在上一篇(http://www.cnblogs.com/wuhao1991/p/4331613.html)的博客中記載了定時的功能,可是集成是沒有成功的,在這篇中,我在解釋下這裏的」集成的含義「,這裏的集成是指:好比我有兩個tomcat(tomcat1,tomcat2),而後如今我先啓動tomcat1,在啓動tomcat2,可是定時查詢的功能在tomcat1上在執行,可是tomcat2上沒有執行;此時我把tomcat1中止調,tomcat2又繼續執行這個定時的功能;因此這裏的集成說白了就是,定時的功能只能執行一個,這兩個tomcat裏賣弄是互斥的關係!java

二:內容技術web

  在上一篇中說過,我在配置集羣的時候,總是出問題,那麼如今我會把這個問題記載下來;下面進行說明吧!spring

application-quartz.xml配置以下apache

<?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以下:tomcat

嚴重: 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:\MyEclipse\wh3\.metadata\.me_tcat7\webapps\chargepile\WEB-INF\classes\applicationContext-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"app

 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>
webapp

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

        </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的都寫了!不枉我研究了兩天啊!

相關文章
相關標籤/搜索