在一个应用程序中,由于我将其从经典的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:
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之前,这一直很好。
ScheduleService
当我用经典的Spring应用程序实现此代码时SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);,巧妙地完成了自动装配服务的工作。
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(this);
在Spring Boot环境中再次进行这项工作需要什么?
编辑:
最后,我选择不再使用Quartz而是使用Spring的ThreadPoolTaskScheduler,该代码已大大简化并且可以按预期工作。
SpringBeanAutowiringSupport使用Web应用程序上下文,在您的情况下不可用。如果需要在石英中使用弹簧管理的豆,则应使用spring提供的石英支架。这将为您提供对所有托管Bean的完全访问权限。有关更多信息,请参见http://docs.spring.io/spring/docs/current/spring- framework- reference/html/scheduling.html上spring docs的石英部分。另请参见下面的示例,将石英与弹簧托管的豆一起使用。示例基于您的代码。因此,您可以使用以下替代弹簧来更改第一个代码段(完成石英初始化)。
创建工作细节工厂
@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(); } }