Java Spring引导:在Quartz作业执行中使用@Service
在一个应用程序中,由于我将它从一个经典的SpringWebApp(部署在系统Tomcat中)转换为一个SpringBoot(V1.2.1)应用程序,因此我面临一个问题,即基于Quartz的计划作业不再工作 我安排这些工作如下: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
// 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(){
....
}