web-dev-qa-db-ja.com

Spring Boot:Quartzジョブの実行で@Serviceを使用する

アプリケーションでは、従来のSpring Webアプリケーション(システムTomcatにデプロイされている)からSpring Boot(V1.2.1)アプリケーションに変換したため、Quartzベースのスケジュールされたジョブが機能しなくなるという問題に直面します。

私はこれらのQuartzジョブを次のようにスケジュールします。

_// My own Schedule object which holds data about what to schedule when
Schedule schedule = scheduleService.get(id of the schedule);

String scheduleId = schedule.getId();

JobKey jobKey = new JobKey(scheduleId);
TriggerKey triggerKey = new TriggerKey(scheduleId);

JobDataMap jobData = new JobDataMap();
jobData.put("scheduleId", scheduleId);

JobBuilder jobBuilder = JobBuilder.newJob(ScheduledActionRunner.class)
    .withIdentity(jobKey)
    .withDescription(schedule.getName())
    .usingJobData(jobData);

JobDetail job = jobBuilder.build();

TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger()
    .forJob(jobKey)
    .withIdentity(triggerKey)
    .withDescription(schedule.getName());

triggerBuilder = triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(schedule.toCronExpression()));

Trigger trigger = triggerBuilder.build();

org.quartz.Scheduler scheduler = schedulerFactoryBean.getScheduler();

scheduler.scheduleJob(job, trigger);
_

ScheduledActionRunner

_@Component
public class ScheduledActionRunner extends QuartzJobBean {

    @Autowired
    private ScheduleService scheduleService;

    public ScheduledActionRunner() {
    }

    @Override
    public void executeInternal(final JobExecutionContext context) throws JobExecutionException {
        SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
        final JobDataMap jobDataMap = context.getMergedJobDataMap();
        final String scheduleId = jobDataMap.getString("scheduleId");
        final Schedule schedule = scheduleService.get(scheduleId);
        // here it goes BANG since scheduleService is null
    }
}
_

ScheduleServiceは、Hibernateからデータをフェッチする従来のSpringサービスです。上で述べたように、これはSpringBootに移行するまでは問題なく機能しました。

このコードを従来のSpringアプリケーションで実装したとき、SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);はサービスの自動配線を処理するためのトリックを実行しました。

Spring Boot環境でこれを再び機能させるには何が必要ですか?

編集:

最後に、SpringのThreadPoolTask​​Schedulerを優先して、Quartzの使用をやめることにしました。コードは大幅に簡素化され、期待どおりに機能します。

10
yglodt

SpringBeanAutowiringSupportは、Webアプリケーションコンテキストを使用しますが、これはあなたのケースでは利用できません。クォーツにスプリングマネージドビーンズが必要な場合は、スプリングが提供するクォーツサポートを使用する必要があります。これにより、すべての管理対象Beanへのフルアクセスが可能になります。詳細については、Spring docsのquartzセクション( http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html )を参照してください。次のSpringマネージドBeanでのクォーツの使用例も参照してください。例はあなたのコードに基づいています。したがって、最初のコードスニペット(クォーツの初期化が行われる場所)を次のSpringの代替手段で変更できます。

ジョブ詳細ファクトリを作成する

@Component
public class ScheduledActionRunnerJobDetailFactory extends JobDetailFactoryBean {

    @Autowired
    private ScheduleService scheduleService;

    @Override
    public void afterPropertiesSet() {
       setJobClass(ScheduledActionRunner.class);
       Map<String, Object> data = new HashMap<String, Object>();
       data.put("scheduleService", scheduleService);
       setJobDataAsMap(data);
       super.afterPropertiesSet();
   }
}

トリガーファクトリを作成する

@Component
public class ActionCronTriggerFactoryBean extends CronTriggerFactoryBean {

   @Autowired
   private ScheduledActionRunnerJobDetailFactory jobDetailFactory;

   @Value("${cron.pattern}")
   private String pattern;

   @Override
   public void afterPropertiesSet() throws ParseException {
       setCronExpression(pattern);
       setJobDetail(jobDetailFactory.getObject());
       super.afterPropertiesSet();
   }

}

そして最後にSchedulerFactoryを作成します

@Component
public class ActionSchedulerFactoryBean extends SchedulerFactoryBean {

   @Autowired
   private ScheduledActionRunnerJobDetailFactory jobDetailFactory;

   @Autowired
   private ActionCronTriggerFactoryBean triggerFactory;

   @Override
   public void afterPropertiesSet() throws Exception {
       setJobDetails(jobDetailFactory.getObject());
       setTriggers(triggerFactory.getObject());
       super.afterPropertiesSet();
   }

}
12
Babl

私の答えはあなたの質問と完全には一致しませんが、Springは別の機能を公開します-任意のサービスでcron式ベースのスケジューラーを開始します。

Spring.Bootを使用すると、配置するだけでスケジューラーを使用するようにアプリケーションを構成できます。

@EnableScheduling
public class Application{
....

その後、@Servicepublic(!)メソッドに次のアノテーションを配置するだけです。

@Service
public class MyService{
...
    @Scheduled(cron = "0 * * * * MON-FRI")
    public void myScheduledMethod(){
    ....
    }
9
Dewfy