虽然在Quartz上有配置Quartz集群Clustering ,但是在Spring中使用Quartz任务调度并支持集群系统却有些问题,下面介绍解决办法:
Spring-1.2.7:spring.jar-1.2.7.jar
Quartz-1.5.2:quartz-1.5.2.jar,quartz-oracle-1.5.2.jar
Oracle10G:
org.springframework.scheduling.quartz.CronTriggerBean与Quartz版本依赖情况:NOTE: This convenience subclass does not work with trigger persistence in Quartz 1.6,due to a change in Quartz's trigger handling. Use Quartz 1.5 if you rely on triggerpersistence based on this class, or the standard Quartz CronTrigger class instead.org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean在使用 org.quartz.impl.jdbcjobstore.JobStoreTX的支持情况: Note: JobDetails created via this FactoryBean are not serializable and thus not suitable for persistent job stores. You need to implement your own Quartz Job as a thin wrapper for each case where you want a persistent job to delegate to a specific service method.
所以,Quartz集群只支持JDBCJobStore存储方式,而MethodInvokingJobDetailFactoryBean不能序列化存储job数据到数据库,所以需要手工编写任务调度类继承QuartzJobBean,否则报如下错误:ERROR [org.springframework.web.context.ContextLoader] Context initialization failed org.springframework.beans.factory.BeanCreationExce ption: Error creating bean with name 'schedulerFactoryBean' defined
in ServletContext resource [/WEB-INF/classes/tim-quartz.xml]: Invocation of init method failed;
nested exception is org.quartz.JobPersistenceException: Couldn't store job: Unable to serialize JobDataMap for insertioninto database because the value of property 'methodInvoker' is not serializable:
org.springframework.scheduling.quartz.MethodInvoki ngJobDetailFactoryBean [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.MethodInvoki ngJobDetailFactoryBean]
# Default Properties file for use by StdSchedulerFactory
# to create a Quartz Scheduler Instance, if a different
# properties file is not explicitly specified.
#org.quartz.scheduler.instanceName = DefaultQuartzScheduler
org.quartz.scheduler.rmi.export = false
org.quartz.scheduler.rmi.proxy = false
org.quartz.scheduler.wrapJobExecutionInUserTransaction = falseorg.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount = 10
org.quartz.threadPool.threadPriority = 5
org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = trueorg.quartz.jobStore.misfireThreshold = 60000
#org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore
#============================================================================
# Configure Main Scheduler Properties
#============================================================================org.quartz.scheduler.instanceId = AUTO
#============================================================================
# Configure JobStore
#============================================================================org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate
org.quartz.jobStore.useProperties = false
org.quartz.jobStore.dataSource = myDS
org.quartz.jobStore.tablePrefix = SYS_org.quartz.jobStore.isClustered = true
org.quartz.jobStore.clusterCheckinInterval = 20000#============================================================================
# Configure Datasources
#============================================================================#org.quartz.dataSource.myDS.jndiURL = java:comp/env/jdbc/psmis
org.quartz.dataSource.myDS.driver = oracle.jdbc.driver.OracleDriver
org.quartz.dataSource.myDS.URL = jdbc:oracle:thin:@10.150.131.33:1521:psmis
org.quartz.dataSource.myDS.user = psmis
org.quartz.dataSource.myDS.password = psmis33
org.quartz.dataSource.myDS.maxConnections = 5
org.quartz.dataSource.myDS.validationQuery=select 0 from dual
package com.sunrise.psmis.sysmanagement.service.impl;
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;import com.sunrise.psmis.webapp.util.ContextUtil;
public class SysScheduleManagerImpl extends QuartzJobBean{
protected final Log logger = LogFactory.getLog(getClass());
private String targetObject;
private String targetMethod;
protected void executeInternal(JobExecutionContext context) throws JobExecutionException{
// System.out.println(jobData.getData() + " 第一个已经被执行了!!");
try
{
ApplicationContext ctx =ContextUtil.getContext();Object otargetObject=ctx.getBean(targetObject);
Method m=null;
try {
m = otargetObject.getClass().getMethod(targetMethod, new Class[] {});
m.invoke(otargetObject, new Object[] {});
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchMethodException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
catch(Exception e)
{
throw new JobExecutionException(e);
}
finally
{
logger.debug("end");
}
}public void setTargetObject(String targetObject) {
this.targetObject = targetObject;
}public void setTargetMethod(String targetMethod) {
this.targetMethod = targetMethod;
}}
//ContextUtil类可以在应用启动的Listener里初始化Spring的ApplicationContext,将ApplicationContext保存在static变量里
com.sunrise.psmis.sysmanagement.service.impl.SysScheduleManagerImpl
com.sunrise.psmis.sysmanagement.service.impl.SysScheduleManagerImpl
前辈,你这篇文章就是及时雨啊。我这几天正在搞这个jobstore。可是现在遇到个问题,放狗都搜不到什么东西。 008-10-08 15:48:09,806 org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:205) - Context initialization failed org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.scheduling.quartz.SchedulerFactoryBean' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Invocation of init method failed; nested exception is org.quartz.SchedulerException: Registration of jobs and triggers failed: closeResultSet Caused by: org.quartz.SchedulerException: Registration of jobs and triggers failed: closeResultSet at org.springframework.scheduling.quartz.SchedulerFactoryBean.registerJobsAndTriggers(SchedulerFactoryBean.java:798) 请前辈指点一二,叩谢
啊,前辈,刚才那个问题莫名其妙就没了。现在是另外一个问题,我的xml定义的contrigger是这样的: 在applicationContext.xml里:
然后在具体模块的xml里定义了: 现在的问题是,当weblogic server起来后,报: 2008-10-08 16:40:00,107 org.quartz.core.JobRunShell.run(JobRunShell.java:202) - Calling execute on job DEFAULT.com.foss.main.customObject.MyMethodInvokingJobD etailFactoryBean#308737 2008-10-08 16:40:00,117 org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFact oryBean.java:242) - Could not invoke method 'null' on target object [null] java.lang.IllegalStateException: prepare() must be called prior to invoke() on MethodInvoker at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:267) at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFactoryBean.java: 224) at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:86) at org.quartz.core.JobRunShell.run(JobRunShell.java:203) at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:520) 2008-10-08 16:40:00,157 org.quartz.core.JobRunShell.run(JobRunShell.java:208) - Job DEFAULT.com.foss.main.customObject.MyMethodInvokingJobDetailFactoryBean#30 8737 threw a JobExecutionException: org.quartz.JobExecutionException: Could not invoke method 'null' on target object [null] [See nested exception: java.lang.IllegalStateException: prepare() mus t be called prior to invoke() on MethodInvoker] 其中,MyMethodInvokingJobDetailFactoryBean是我wripper的MethodInvokingJobDetailFactoryBean 是不是我xml里config的job不对呢?请前辈指教 true 0 0/5 * * * ?
你的错误报:Could not invoke method 'null' on target object [null] ; 说明的你的配置有问题。如果你是要集群环境跑,那就不能用MethodInvokingJobDetailFactoryBean,好像你的MyMethodInvokingJobDetailFactoryBean也是继承这个的。如果不是集群环境,那么用MethodInvokingJobDetailFactoryBean很方便。
如果不是集群环境参考:
大侠,我是要在集群环境跑。我的目的是要在cluster的环境下,同一时间只能有一个app server 跑scheduled 好的一个job, 我做的那个MyMethodInvokingJobDetailFactoryBean的确是继承的MethodInvokingJobDetailFactoryBean,因为MethodInvokingJobDetailFactoryBean不是序列化的。但是我在MyMethodInvokingJobDetailFactoryBean不知道该怎么重写execute()。。。。。。。 刚才又去试了你给的SysScheduleManagerImpl.java,可是在做ContextUtil的遇到路径问题。在我的applicationContext里,有定义quartz.property的路径:
这个在weblogic parse xml file的时候是工作的。但是当用FileSystemXmlApplicationContext(xml file list)的时候,就找不到了。我要是改成FileSystemXmlApplicationContext能找到的,weblogic parse的时候就找不到了。晕啊
大侠,我终于搞出来了。没有用那个ContextUtil 而是在xml file里面加一句:
applicationContext 然后在SysScheduleManagerImpl.java里: ApplicationContext ctx = (ApplicationContext) context.getScheduler().getContext().get("applicationContext"); Object otargetObject=ctx.getBean(targetObject);