Реализация Spring 3 Quartz 2 больше не поддерживает запросыRecovery

Согласно документации Quartz 2.

RequestsRecovery — если задание «запрашивает восстановление», и оно выполняется во время «жесткого выключения» планировщика (т. е. процесс, который выполняется во время сбоя, или машина выключается) , затем выполняется повторно при повторном запуске планировщика. В этом случае метод JobExecutionContext.isRecovering() вернет значение true.

Spring3 поддерживает как Quartz 1.x, так и Quartz 2.x. Если мы используем Quartz 1.x, нам нужно использовать следующую конфигурацию для создания JobDetail bean-компонента:

<bean id="ldapSynch" class="org.springframework.scheduling.quartz.JobDetailBean">
    <property name="jobClass" value="com.edfx.adb.scheduling.job.LDAPSynchronizer" />
    <property name="requestsRecovery" value="true" />       
</bean>

Внутренне org.springframework.scheduling.quartz.JobDetailBean расширяет org.quartz.JobDetail, а в Quartz 1.x org.quartz.JobDetail имеет сеттер public void setRequestsRecovery(boolean shouldRecover).

Но если мы используем Quartz 2.x реализацию Spring3, то вышеупомянутая конфигурация изменится следующим образом:

<bean id="ldapSynch" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
    <property name="jobClass" value="com.edfx.adb.scheduling.job.LDAPSynchronizer" />
    <property name="requestsRecovery" value="true" />       
</bean>

А также в Quartz 2.x нет такого класса org.quartz.JobDetail, вместо этого есть interface и, в конце концов, org.springframework.scheduling.quartz.JobDetailFactoryBean больше не принимает параметр <property name="requestsRecovery" value="true" />.

Как мы могли передать этот важный parameter планировщику Quartz?


person Tapas Bose    schedule 31.12.2012    source источник


Ответы (2)


Изучив исходный код класса org.springframework.scheduling.quartz.JobDetailFactoryBean и исходный код Quartz 2.0, я обнаружил, что в org.springframework.scheduling.quartz.JobDetailFactoryBean есть вид init method, который равен public void afterPropertiesSet(); внутри этого метода создается экземпляр org.quartz.JobDetail. К счастью, этот экземпляр org.quartz.JobDetail может быть доступен через метод public JobDetail getObject() класса org.springframework.scheduling.quartz.JobDetailFactoryBean.

В Quartz 2.0 класс org.quartz.impl.JobDeialImpl реализует интерфейс org.quartz.JobDetail; поэтому экземпляр org.quartz.JobDetail в org.springframework.scheduling.quartz.JobDetailFactoryBean на самом деле является экземпляром org.quartz.impl.JobDeialImpl.

Поэтому я создал класс com.edfx.adb.scheduling.ADBJobDetailFactoryBean, который расширяет org.springframework.scheduling.quartz.JobDetailFactoryBean и переопределяет метод afterPropertiesSet() следующим образом:

package com.edfx.adb.scheduling;

import org.quartz.impl.JobDetailImpl;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;

public class ADBJobDetailFactoryBean extends JobDetailFactoryBean {

    private boolean requestsRecovery;

    public ADBJobDetailFactoryBean() {
        super();
    }

    @Override
    public void afterPropertiesSet() {
        super.afterPropertiesSet();
        JobDetailImpl jobDetail = (JobDetailImpl) getObject();
        jobDetail.setRequestsRecovery(isRequestsRecovery());
    }

    public boolean isRequestsRecovery() {
        return requestsRecovery;
    }

    public void setRequestsRecovery(boolean requestsRecovery) {
        this.requestsRecovery = requestsRecovery;
    }
}

И изменил конфигурацию spring bean следующим образом:

<bean id="ldapSynch" class="com.edfx.adb.scheduling.ADBJobDetailFactoryBean">
    <property name="jobClass" value="com.edfx.adb.scheduling.job.LDAPSynchronizer" />
    <property name="requestsRecovery" value="true" />       
</bean>

И вуаля. Я проверил это, остановив работающий сервер, пока планировщик выполнял задачу, и когда я перезапустил сервер, планировщик начал выполнять незавершенное задание.

Надеюсь, это поможет кому-то.

person Tapas Bose    schedule 31.12.2012

@tapas-bose, ища информацию о кварце, я наткнулся на ваш пост. Похоже, что Spring 3.2 поддерживает настройку свойства requestsRecovery. Я не знаю, какая версия Spring 3.? вы упомянули в своем ответе, с которым вы столкнулись с проблемой.

Я установил свойство requestRecovery напрямую через инъекцию установщика, и это сработало для меня.

  <bean name="continousMonitoringProfileNotificationPushProcessing"     class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
  <property name="jobClass" value="com.mycompany.projectApp.jobs.ContinousMonitoringNotificationPushJobBean" />
    <property name="jobDataAsMap">
        <map>
            <entry key="executionSuccessful" value="true"/>
        </map>
    </property>
    <property name="durability" value="true" /> 
    <property name="requestsRecovery" value="true"/>
 </bean>

Когда я декомпилировал код для JobDetailFactoryBean, он переопределяет метод afterPropertiesSet, который создает экземпляр JObDetailImpl и устанавливает запросыRecovery (фрагмент декомпилированного кода, как показано ниже)

 public class JobDetailFactoryBean implements FactoryBean<JobDetail>, BeanNameAware, ApplicationContextAware, InitializingBean
 {
 private String name;
 private String group;
 private Class jobClass;
 private JobDataMap jobDataMap = new JobDataMap();
 private boolean durability = false;
 private boolean requestsRecovery = false;

...

.. 

..


 public void afterPropertiesSet()
{
  if (this.name == null) {
  this.name = this.beanName;
 }
  if (this.group == null) {
  this.group = "DEFAULT";
 }
if (this.applicationContextJobDataKey != null) {
 if (this.applicationContext == null) {
        throw new IllegalStateException("JobDetailBean needs to be set up in ApplicationContext to be able to handle an 'applicationContextJobDataKey'");
    }
 getJobDataMap().put(this.applicationContextJobDataKey, this.applicationContext);
 }
 Class<?> jobDetailClass;
 try
 {
      jobDetailClass = getClass().getClassLoader().loadClass("org.quartz.impl.JobDetailImpl");
  }
  catch (ClassNotFoundException ex) {
      jobDetailClass = JobDetail.class;
  }
  BeanWrapper bw = new BeanWrapperImpl(jobDetailClass);
  MutablePropertyValues pvs = new MutablePropertyValues();
  pvs.add("name", this.name);
  pvs.add("group", this.group);
  pvs.add("jobClass", this.jobClass);
  pvs.add("jobDataMap", this.jobDataMap);
  pvs.add("durability", Boolean.valueOf(this.durability));
  pvs.add("requestsRecovery", Boolean.valueOf(this.requestsRecovery));

Поэтому нам не нужно вручную расширять класс JobFactoryBean и задавать свойство requestRecovery.

person SandyStack    schedule 11.12.2014