Java 在集群系统中使用quartz时出现nullPointerException,但在删除数据库配置时,效果良好

Java 在集群系统中使用quartz时出现nullPointerException,但在删除数据库配置时,效果良好,java,quartz-scheduler,quartz,Java,Quartz Scheduler,Quartz,这是我的石英配置: @Bean public SchedulerFactoryBean startQuartz(DataSource dataSource, PlatformTransactionManager annotationDrivenTransactionManager, CronTriggerFactoryBean remoteProjectTrigger, ApplicationContext appl

这是我的石英配置:

@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
methodInvoker
为空

当移除
schedulerFactoryBean.setDataSource(数据源)
schedulerFactoryBean.setTransactionManager(annotationDrivenTransactionManager)
schedulerFactoryBean.setQuartzProperties(quartzProperties())


此配置将起作用。任何人都可以处理:)

这是因为调用JobDetailFactoryBean的类MethodInvoking无法序列化到数据库,
spring上下文支持
没有提供序列化版本,假设抛出一个
SerializationException
而不是
NullPointerException
,我不明白这一点。 但只有解决这个问题,我找到两种方法

1、 overwrite
MethodInvokingJobDetailFactoryBean
serializable版本,您可以在
https://jira.spring.io/browse/SPR-3797
,但对于最新的quartz版本(2.2.3),您可以进行一些更新工作

@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;
}
}
@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
}
我使用
lombok
注释。 然后使用此类替换调用JobDetailFactoryBean的
方法,配置如下

@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;
}
}
@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
}