这是我的石英配置:
@Bean
public SchedulerFactoryBean startQuartz(DataSource dataSource, PlatformTransactionManager annotationDrivenTransactionManager,
CronTriggerFactoryBean remoteProjectTrigger, ApplicationContext applicationContext) throws IOException {
SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean();
schedulerFactoryBean.setDataSource(dataSource);
schedulerFactoryBean.setTransactionManager(annotationDrivenTransactionManager);
schedulerFactoryBean.setOverwriteExistingJobs(false);
schedulerFactoryBean.setQuartzProperties(quartzProperties());
schedulerFactoryBean.setTriggers(remoteProjectTrigger.getObject());
schedulerFactoryBean.setApplicationContext(applicationContext);
return schedulerFactoryBean;
}
@Bean(name = "detailFactoryBean")
public MethodInvokingJobDetailFactoryBean detailFactoryBean(){
MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean ();
bean.setTargetBeanName("quartzRemoteProject");
bean.setTargetMethod ("run");
bean.setConcurrent (false);
return bean;
}
@Bean
public CronTriggerFactoryBean remoteProjectTrigger(MethodInvokingJobDetailFactoryBean detailFactoryBean){
CronTriggerFactoryBean trigger = new CronTriggerFactoryBean ();
trigger.setJobDetail (detailFactoryBean.getObject ());
trigger.setCronExpression ("0/5 * * ? * *");
return trigger;
}
@Bean("quartzRemoteProject")
public QuartzRemoteProject quartzRemoteProject(){
return new QuartzRemoteProject();
}
public Properties quartzProperties() throws IOException {
Properties prop = new Properties();
prop.put("quartz.scheduler.instanceName", "ServerScheduler");
prop.put("org.quartz.scheduler.instanceId", "AUTO");
prop.put("org.quartz.scheduler.skipUpdateCheck", "true");
prop.put("org.quartz.scheduler.instanceId", "CLUSTERED");
prop.put("org.quartz.scheduler.jobFactory.class", "org.quartz.simpl.SimpleJobFactory");
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
prop.put("org.quartz.jobStore.isClustered", "true");
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "5");
return prop;
}
此配置将出现异常
org.quartz.SchedulerException: Job threw an unhandled exception.
at org.quartz.core.JobRunShell.run(JobRunShell.java:213) ~[quartz-2.2.3.jar:na]
at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573) [quartz-2.2.3.jar:na]
Caused by: java.lang.NullPointerException: null
at org.springframework.scheduling.quartz.JobMethodInvocationFailedException.<init>(JobMethodInvocationFailedException.java:40) ~[spring-context-support-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean$MethodInvokingJob.executeInternal(MethodInvokingJobDetailFactoryBean.java:271) ~[spring-context-support-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.scheduling.quartz.QuartzJobBean.execute(QuartzJobBean.java:75) ~[spring-context-support-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.quartz.core.JobRunShell.run(JobRunShell.java:202) ~[quartz-2.2.3.jar:na]
... 1 common frames omitted
我发现问题出在MethodInvokingJobDetailFactoryBean.class的内部类MethodInvokingJob
context.setResult(this.methodInvoker.invoke());
methodInvoker
为空;
删除时
schedulerFactoryBean.setDataSource(dataSource);
schedulerFactoryBean.setTransactionManager(annotationDrivenTransactionManager);
schedulerFactoryBean.setQuartzProperties(quartzProperties());
此配置将起作用。任何人都可以发言:)
答案 0 :(得分:0)
这是因为类MethodInvokingJobDetailFactoryBean无法序列化到数据库,
spring-context-support
没有提供序列化版本,假设抛出SerializationException
而不是NullPointerException
,我不知道这个。
但只有解决这个问题,我找到了两种方法。
1,覆盖MethodInvokingJobDetailFactoryBean
可序列化版本,你可以在中找到样本
https://jira.spring.io/browse/SPR-3797
,但是对于最新的石英版本(2.2.3),你可以做一些更新工作。然后将配置MethodInvokingJobDetailFactoryBean更改为BeanInvokingJobDetailFactoryBean,如下所示
@Bean(name = "jobDetailFactoryBean")
public BeanInvokingJobDetailFactoryBean detailFactoryBean(){
BeanInvokingJobDetailFactoryBean bean = new BeanInvokingJobDetailFactoryBean ();
bean.setTargetBean("quartzRemoteProject");
bean.setTargetMethod ("run");
bean.setDurable(true);
bean.setShouldRecover(true);
bean.setConcurrent (false);
return bean;
}
2,自己写QuartzJobBean
,就像这样
@Log4j
@NoArgsConstructor
public class MyDetailQuartzJobBean extends QuartzJobBean {
private String targetObject;
private String targetMethod;
private ApplicationContext ctx;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
Object bean = ctx.getBean(targetObject);
Method m = bean.getClass().getMethod(targetMethod);
m.invoke(bean, null);
} catch (Exception e) {
e.printStackTrace();
}
}
public void setApplicationContext(ApplicationContext applicationContext) {
this.ctx = applicationContext;
}
public void setTargetObject(String targetObject) {
this.targetObject = targetObject;
}
public void setTargetMethod(String targetMethod) {
this.targetMethod = targetMethod;
}
}
我使用lombok
注释。
然后使用此类替换MethodInvokingJobDetailFactoryBean
,像这样配置
@Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobClass(MyDetailQuartzJobBean.class);
Map map=new HashMap<>();
map.put("targetObject","quartzRemoteProject");
map.put("targetMethod","run");
jobDetailFactoryBean.setJobDataAsMap(map);
jobDetailFactoryBean.setDurability(true);
return jobDeta
}
ps:您必须添加quartz-jobs
的第二个解决方案,否则无法找到JobDetailFactoryBean
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.2.3</version>
</dependency>