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

ygl*_*odt 9 java spring hibernate quartz-scheduler spring-boot

在一个应用程序中,由于我将它从经典的Spring webapp(部署在系统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);
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

ScheduleService是一个经典的Spring服务,它从Hibernate中获取数据.正如我上面所说,这一直很好,直到我转移到Spring Boot.

当我使用经典的Spring应用程序实现此代码时,SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);可以处理自动装配服务的技巧.

在Spring Boot环境中再次使用它需要什么?

编辑:

最后,我选择放弃使用Quartz而不是Spring的ThreadPoolTask​​Scheduler.代码非常简单,并且按预期工作.

Bab*_*abl 12

SpringBeanAutowiringSupport使用Web应用程序上下文,在您的情况下不可用.如果您需要石英中的弹簧管理豆,您应该使用弹簧提供的石英支撑.这将使您可以完全访问所有托管bean.有关详细信息,请参阅http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html上的spring docs中的quartz部分.另请参阅以下使用Quart with spring managed beans的示例.示例基于您的代码.因此,您可以使用以下弹簧替代方案更改第一个代码段(完成石英初始化的位置).

创建工作细节工厂

@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();
   }
}
Run Code Online (Sandbox Code Playgroud)

创建触发器工厂

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

}
Run Code Online (Sandbox Code Playgroud)

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

}
Run Code Online (Sandbox Code Playgroud)


Dew*_*wfy 9

我的回答并不完全符合您的问题,但是Spring为您提供了另一种能力 - 在任何服务上启动基于cron-expression的调度程序.

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

@EnableScheduling
public class Application{
....
Run Code Online (Sandbox Code Playgroud)

之后只是注释public(!)方法的注释@Service

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

  • 谢谢,我知道这一点,并已将它用于静态的Schedules.我上面描述的问题来自可以由用户设置的Schedules,所以我需要在运行时添加/编辑/删除它们,据我所知,使用@Scheduled注释是不可能的. (3认同)