Получил nullPointerException при использовании кварца в кластерной системе, но при удалении конфигурации базы данных он работает нормально
Это мой кварцевый конфиг:
@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());
этот конфиг будет работать. любой может помочь
1 ответ
Это потому, что класс 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>