在Spring中使用Quartz任务调度支持集群
虽然在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 QuartzCronTrigger
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' definedin 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]
类路径上的quartz.properties:
# 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
创建数据库表结构:在下载的包quartz-1.5.2.zip\quartz-1.5.2\docs\dbTables\tables_oracle.sql
调度类,SysScheduleManagerImpl.java:
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变量里
applicationContext-service.xml:
<bean id="exampleJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>com.sunrise.psmis.sysmanagement.service.impl.SysScheduleManagerImpl</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="targetObject" value="ecOwnUnstopWorksheetManager"/>
<entry key="targetMethod" value="execSyncPaymeny"/>
</map>
</property>
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="exampleJob" />
<!-- run every morning at 6 AM -->
<property name="cronExpression" value="0 2 * * * ?" />
</bean>
<bean id="seqJob" class="org.springframework.scheduling.quartz.JobDetailBean">
<property name="jobClass">
<value>com.sunrise.psmis.sysmanagement.service.impl.SysScheduleManagerImpl</value>
</property>
<property name="jobDataAsMap">
<map>
<entry key="targetObject" value="sysIdManager"/>
<entry key="targetMethod" value="callProSeqEvalute"/>
</map>
</property>
</bean>
<bean id="seqTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="seqJob" />
<!-- run every morning at 6 AM -->
<property name="cronExpression" value="0 0 0,1,2 * * ?" />
</bean><bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTrigger" />
<ref bean="seqTrigger"/>
</list>
</property>
<property name="schedulerContextAsMap">
<map>
<entry key="sysIdManager">
<ref bean="sysIdManager" />
</entry>
<entry key="ecOwnUnstopWorksheetManager">
<ref bean="ecOwnUnstopWorksheetManager" />
</entry>
</map>
</property>
</bean>
Re: 在Spring中使用Quartz任务调度支持集群
Re: 在Spring中使用Quartz任务调度支持集群
Re: 在Spring中使用Quartz任务调度支持集群
<bean id="exampleJob" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="ecOwnUnstopWorksheetManager" />
<property name="targetMethod" value="execSyncPaymeny" />
<property name="concurrent" value="false" />
</bean>
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="exampleJob" />
<!-- run every morning at 6 AM -->
<property name="cronExpression" value="0 2 * * * ?" />
</bean>