简体   繁体   English

Spring Boot:在Quartz作业执行中使用@Service

[英]Spring Boot: Using a @Service in Quartz job execution

In an application, since I converted it from a classical Spring webapp (deployed in a system Tomcat) to a Spring Boot (V1.2.1) application I face the problem that the Quartz-based scheduled jobs are not working anymore. 在一个应用程序中,由于我将它从经典的Spring webapp(部署在系统Tomcat中)转换为Spring Boot(V1.2.1)应用程序,我面临的问题是基于Quartz的预定作业不再起作用。

I schedule these Quartz jobs like this: 我安排这些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 : 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 is a classical Spring service which fetches data from Hibernate. ScheduleService是一个经典的Spring服务,它从Hibernate获取数据。 As I said above, this worked fine until I moved to Spring Boot. 正如我上面所说,这一直很好,直到我转移到Spring Boot。

When I implemented this code with the classical Spring application, SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); 当我使用经典的Spring应用程序实现此代码时, SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this); did the trick to take care of autowiring the service. 做了诀窍来照顾自动装配服务。

What is needed to make this work again in the Spring Boot environment ? 在Spring Boot环境中再次使用它需要什么?

Edit: 编辑:

At the end I chose to move away from using Quartz in favour of Spring's ThreadPoolTaskScheduler.The code was much simplified and it works as expected. 最后,我选择放弃使用Quartz而不是Spring的ThreadPoolTask​​Scheduler。代码非常简单,并且按预期工作。

The SpringBeanAutowiringSupport uses the web application context, which is not available in your case. SpringBeanAutowiringSupport使用Web应用程序上下文,在您的情况下不可用。 If you need a spring managed beans in the quartz you should use the quartz support provided by spring. 如果您需要石英中的弹簧管理豆,您应该使用弹簧提供的石英支撑。 This will give you full access to all the managed beans. 这将使您可以完全访问所有托管bean。 For more info see the quartz section at spring docs at http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html . 有关详细信息,请参阅http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html上的spring docs中的quartz部分。 Also see following example of usage quartz with spring managed beans. 另请参阅以下使用Quart with spring managed beans的示例。 Example is based on your code. 示例基于您的代码。 So you can change the first code snippet (where the quartz initialization is done) with follwoing spring alternatives. 因此,您可以使用以下弹簧替代方案更改第一个代码段(完成石英初始化的位置)。

Create job detail factory 创建工作细节工厂

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

Create the trigger factory 创建触发器工厂

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

}

And finally create the SchedulerFactory 最后创建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();
   }

}

My answer not fully matches to you question, but Spring expose you another ability - to start cron-expression based scheduler on any service. 我的回答并不完全符合您的问题,但是Spring为您提供了另一种能力 - 在任何服务上启动基于cron-expression的调度程序。

Using Spring.Boot you can configure your application to use scheduler by simple placing 使用Spring.Boot,您可以通过简单的放置将应用程序配置为使用调度程序

@EnableScheduling
public class Application{
....

After that just place following annotation on public (!) method of @Service 之后只是注释@Service public (!)方法

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM