0

这是我的石英配置:

@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());

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

4

1 回答 1

0

这是因为类 MethodInvokingJobDetailFactoryBean 无法序列化到数据库, spring-context-support没有提供序列化版本,假设抛出一个SerializationException而不是NullPointerException,我不明白这一点。但只能解决这个问题,我找到了两种方法。

1、覆盖MethodInvokingJobDetailFactoryBean可序列化版本,你可以在里面找到一个示例 https://jira.spring.io/browse/SPR-3797 ,但是对于最新的quartz版本(2.2.3),你可以做一些更新工作。然后将config 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,config 像这样

@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>
于 2017-03-28T02:23:19.787 回答