Spring 引导:在 Quartz 作业执行中使用 @Service
Spring Boot: Using a @Service in Quartz job execution
在应用程序中,由于我将其从经典的 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);
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 引导环境中再次运行需要什么?
编辑:
最后,我选择不再使用 Quartz,转而使用 Spring 的 ThreadPoolTaskScheduler.The 代码大大简化了,并且按预期工作。
SpringBeanAutowiringSupport 使用 Web 应用程序上下文,这在您的情况下不可用。如果您需要 spring 石英中的托管 bean,您应该使用 spring 提供的石英支持。这将使您能够完全访问所有托管 bean。
有关详细信息,请参阅 spring 文档中的石英部分 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html。另请参阅以下使用 quartz 与 spring 托管 bean 的示例。示例基于您的代码。
因此,您可以使用以下 spring 替代方案更改第一个代码片段(完成石英初始化的地方)。
创建作业详细信息工厂
@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();
}
}
我的回答与您的问题不完全匹配,但Spring向您展示了另一种能力——在任何服务上启动基于 cron-expression 的调度程序。
使用 Spring.Boot 您可以通过简单地放置
配置您的应用程序以使用调度程序
@EnableScheduling
public class Application{
....
之后,只需在 @Service
的 public
(!) 方法上放置以下注释
@Service
public class MyService{
...
@Scheduled(cron = "0 * * * * MON-FRI")
public void myScheduledMethod(){
....
}
在应用程序中,由于我将其从经典的 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);
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 引导环境中再次运行需要什么?
编辑:
最后,我选择不再使用 Quartz,转而使用 Spring 的 ThreadPoolTaskScheduler.The 代码大大简化了,并且按预期工作。
SpringBeanAutowiringSupport 使用 Web 应用程序上下文,这在您的情况下不可用。如果您需要 spring 石英中的托管 bean,您应该使用 spring 提供的石英支持。这将使您能够完全访问所有托管 bean。 有关详细信息,请参阅 spring 文档中的石英部分 http://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html。另请参阅以下使用 quartz 与 spring 托管 bean 的示例。示例基于您的代码。 因此,您可以使用以下 spring 替代方案更改第一个代码片段(完成石英初始化的地方)。
创建作业详细信息工厂
@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();
}
}
我的回答与您的问题不完全匹配,但Spring向您展示了另一种能力——在任何服务上启动基于 cron-expression 的调度程序。
使用 Spring.Boot 您可以通过简单地放置
配置您的应用程序以使用调度程序@EnableScheduling
public class Application{
....
之后,只需在 @Service
public
(!) 方法上放置以下注释
@Service
public class MyService{
...
@Scheduled(cron = "0 * * * * MON-FRI")
public void myScheduledMethod(){
....
}