Java Spring引导:在Quartz作业执行中使用@Service

Java Spring引导:在Quartz作业执行中使用@Service,java,spring,hibernate,spring-boot,quartz-scheduler,Java,Spring,Hibernate,Spring Boot,Quartz Scheduler,在一个应用程序中,由于我将它从一个经典的SpringWebApp(部署在系统Tomcat中)转换为一个SpringBoot(V1.2.1)应用程序,因此我面临一个问题,即基于Quartz的计划作业不再工作 我安排这些工作如下: // My own Schedule object which holds data about what to schedule when Schedule schedule = scheduleService.get(id of the schedule); Str

在一个应用程序中,由于我将它从一个经典的SpringWebApp(部署在系统Tomcat中)转换为一个SpringBoot(V1.2.1)应用程序,因此我面临一个问题,即基于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
是一个经典的Spring服务,它从Hibernate获取数据。 正如我上面所说的,在我转到SpringBoot之前,这一切都很好

当我用经典的Spring应用程序实现这段代码时,
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this)完成了自动连接服务的技巧

在Spring引导环境中,需要什么才能使它再次工作

编辑:


最后,我选择放弃使用Quartz,转而使用Spring的ThreadPoolTaskScheduler。代码简化得多,工作正常。

SpringBeanAutowiringSupport使用web应用程序上下文,这在您的案例中不可用。如果您在quartz中需要spring管理的bean,您应该使用spring提供的quartz支持。这将使您能够完全访问所有托管bean。 有关更多信息,请参阅spring文档中的石英部分。另请参见下面的使用spring托管bean的示例。示例基于您的代码。 因此,您可以使用以下spring替代方案更改第一个代码段(完成quartz初始化的地方)

创建作业详细信息工厂

@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();
   }
}
最后创建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();
   }

}

我的答案和您的问题并不完全相符,但Spring向您展示了另一种能力——在任何服务上启动基于cron表达式的调度器

使用Spring.Boot,您可以通过简单的放置来配置应用程序以使用调度程序

@EnableScheduling
public class Application{
....
之后,只需在
@Service
public
(!)方法上放置以下注释即可

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

谢谢@Babl的回答。在尝试您提出的代码之前,我唯一也是最后一个问题是:为什么它在将应用程序更改为使用Spring Boot之前工作?在Spring Boot之前,它已经基于JavaConfig和Spring 4.1,并且调度工作正常。正如我前面提到的,SpringBeanAutowiringSupport使用web应用程序上下文查找bean并将其注入到对象中,但是由于Spring Boot应用程序不完全是web应用程序,因此上下文为空。因此,如果您在调试级别为SpringBeanAutowiringSupport启用日志,您将看到一条devug消息,它告诉您目标类不是在SpringWeb应用程序中构造的。任何打开spring调试级别的方法都会为您提供有关该问题的大量内部信息;)谢谢你的详细解释!谢谢,我知道这一点,并已将其用于静态时间表。我上面描述的问题来自用户可以设置的计划,因此我需要在运行时添加/编辑/删除它们,据我所知,这在@Scheduled注释中是不可能的。@agilob您到底想问什么?你可以发布一个独立的问题并给我链接。起源问题未提及“多集群”。但也许你可以看看SpringCloud(带有全局锁和领导人选举主题)的评论,以回答Dewfy的问题(因为我没有足够的代表发表评论):我还必须用@Transactional注释标记该方法,因为我得到了一个错误,即hibernate会话没有附加。
@Service
public class MyService{
...
    @Scheduled(cron = "0 * * * * MON-FRI")
    public void myScheduledMethod(){
    ....
    }