在一个应用程序中,由于我将它从经典的Spring webapp(部署在系统Tomcat中)转换为Spring Boot(V1.2.1)应用程序,因此我遇到了基于Quartz的预定作业不再工作的问题。 / p>
我安排这样的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中获取数据。
正如我上面所说的,这一直很好,直到我转到Spring Boot。
当我使用经典的Spring应用程序实现此代码时,SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
完成了处理自动装配服务的技巧。
在Spring Boot环境中再次使用它需要什么?
修改
最后,我选择放弃使用Quartz而不是Spring的ThreadPoolTaskScheduler。代码非常简化,并且按预期工作。
答案 0 :(得分:12)
SpringBeanAutowiringSupport使用Web应用程序上下文,在您的情况下不可用。如果您需要石英中的弹簧管理豆,您应该使用弹簧提供的石英支撑。这将使您可以完全访问所有托管bean。 有关详细信息,请参阅http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html春季文档中的石英部分。另请参阅以下使用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();
}
}
创建触发器工厂
@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();
}
}
答案 1 :(得分:9)
我的回答并不完全符合您的问题,但Spring为您提供了另一种能力 - 在任何服务上启动基于cron-expression的调度程序。
使用Spring.Boot,您可以通过简单的放置
将应用程序配置为使用调度程序@EnableScheduling
public class Application{
....
之后,只需按照public
@Service
(!)方法进行注释
@Service
public class MyService{
...
@Scheduled(cron = "0 * * * * MON-FRI")
public void myScheduledMethod(){
....
}