1.问题描述
由于spring的bug(具体原因可在github上搜索),使用MethodInvokingJobDetailFactoryBean配置jobdetail后,启动quartz集群时此类无法序列化
2.解决方案
根据git上提供的解决办法,重新MethodInvokingJobDetailFactoryBean为BeanInvokingJobDetailFactoryBean,但git上提供的代码在高版本中不适用。下面贴出修改后的代码
@Component
public class BeanInvokingJobDetailFactoryBean implements
FactoryBean, BeanNameAware, InitializingBean, ApplicationContextAware
{
protected static ApplicationContext applicationContext;
private Log logger = LogFactory.getLog(getClass());
private String group = Scheduler.DEFAULT_GROUP;
private boolean concurrent = true;
private boolean durable = false;
private boolean volatility = false;
private boolean shouldRecover = false;
private String[] jobListenerNames;
private String beanName;
private JobDetail jobDetail;
private String targetBean;
private String targetMethod;
private Object[] arguments;
// targetBean getter setter 省略
// targetMethod getter setter 省略
@Override
public JobDetail getObject() throws Exception
{
return jobDetail;
}
@Override
public Class getObjectType()
{
return JobDetail.class;
}
@Override
public boolean isSingleton()
{
return true;
}
@Override
public void setBeanName(String beanName)
{
this.beanName = beanName;
}
@Override
public void afterPropertiesSet() throws Exception
{
try
{
logger.debug("start");
logger.debug("Creating JobDetail "+beanName);
JobDetailImpl jdi = new JobDetailImpl();
jdi.setName(beanName);
jdi.setGroup(group);
jdi.setJobClass(concurrent ? BeanInvokingJob.class :
StatefulBeanInvokingJob.class);
jdi.setDurability(durable);
// jdi.setVolatility(volatility);
jdi.setRequestsRecovery(shouldRecover);
this.jobDetail = jdi;
jobDetail.getJobDataMap().put("targetBean", targetBean);
jobDetail.getJobDataMap().put("targetMethod", targetMethod);
jobDetail.getJobDataMap().put("arguments", arguments);
logger.debug("Registering JobListener names with JobDetail object "+beanName);
// if (this.jobListenerNames != null) {
// for (int i = 0; i < this.jobListenerNames.length; i++) {
// this.jobDetail.addJobListener(this.jobListenerNames[i]);
// }
// }
logger.info("Created JobDetail: "+jobDetail+"; targetBean: "+
targetBean+"; targetMethod: "+targetMethod+"; arguments: "+arguments+";");
}
finally
{
logger.debug("end");
}
}
public void setConcurrent(boolean concurrent)
{
this.concurrent = concurrent;
}
public void setDurable(boolean durable)
{
this.durable = durable;
}
public void setGroup(String group)
{
this.group = group;
}
public void setJobListenerNames(String[] jobListenerNames)
{
this.jobListenerNames = jobListenerNames;
}
public void setShouldRecover(boolean shouldRecover)
{
this.shouldRecover = shouldRecover;
}
public void setVolatility(boolean volatility)
{
this.volatility = volatility;
}
@Override
public void setApplicationContext(ApplicationContext context) throws BeansException
{
applicationContext = context;
}
public void setArguments(Object[] arguments)
{
this.arguments = arguments;
}
public void setJobDetail(JobDetail jobDetail) {
this.jobDetail = jobDetail;
}
public void setTargetBean(String targetBean) {
this.targetBean = targetBean;
}
public void setTargetMethod(String targetMethod) {
this.targetMethod = targetMethod;
}
public static class BeanInvokingJob implements Job
{
protected Log logger = LogFactory.getLog(getClass());
@Override
public void execute(JobExecutionContext context) throws JobExecutionException
{
try
{
logger.debug("start");
String targetBean = context.getMergedJobDataMap().getString("targetBean");
logger.debug("targetBean is "+targetBean);
if(targetBean==null){
throw new JobExecutionException("targetBean cannot be null.", false);
}
String targetMethod = context.getMergedJobDataMap().getString("targetMethod");
logger.debug("targetMethod is "+targetMethod);
if(targetMethod==null){
throw new JobExecutionException("targetMethod cannot be null.", false);
}
Object argumentsObject = context.getMergedJobDataMap().get("arguments");
Object[] arguments = (argumentsObject instanceof String) ? null :
(Object[])argumentsObject;
logger.debug("arguments array is "+arguments);
Object bean = applicationContext.getBean(targetBean);
logger.debug("applicationContext resolved bean name/id '"+targetBean+"' to "+bean);
MethodInvoker beanMethod = new MethodInvoker();
beanMethod.setTargetObject(bean);
beanMethod.setTargetMethod(targetMethod);
beanMethod.setArguments(arguments);
beanMethod.prepare();
logger.info("Invoking Bean: "+targetBean+"; Method: "+
targetMethod+"; arguments: "+arguments+";");
beanMethod.invoke();
}
catch(JobExecutionException e)
{
throw e;
}
catch(Exception e)
{
throw new JobExecutionException(e);
}
finally
{
logger.debug("end");
}
}
}
public static class StatefulBeanInvokingJob extends BeanInvokingJob implements StatefulJob
{
// No additional functionality; just needs to implement StatefulJob.
}
}