我对Quartz很新,现在我需要在Spring Web应用程序中安排一些工作。
我知道Spring + Quartz集成(我使用的是Spring v 3.1.1),但我想知道这是否是正确的方法。
特别是我需要在数据库中保留我的计划任务,以便在重新启动应用程序时重新初始化它们。
Spring调度包装器是否提供了一些实用程序来执行此操作? 你能建议我采用一些“众所周知的”方法吗?
答案 0 :(得分:12)
这是我处理这种情况的一种方式。
首先在我的Spring配置中指定一个SchedulerFactoryBean
,我可以从中Scheduler
注入其他bean。
<bean name="SchedulerFactory"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="applicationContextSchedulerContextKey">
<value>applicationContext</value>
</property>
</bean>
然后,当我在应用程序中创建作业时,我将作业的详细信息存储在数据库中。这个服务由我的一个控制器调用,它安排工作:
@Component
public class FollowJobService {
@Autowired
private FollowJobRepository followJobRepository;
@Autowired
Scheduler scheduler;
@Autowired
ListableBeanFactory beanFactory;
@Autowired
JobSchedulerLocator locator;
public FollowJob findByClient(Client client){
return followJobRepository.findByClient(client);
}
public void saveAndSchedule(FollowJob job) {
job.setJobType(JobType.FOLLOW_JOB);
job.setCreatedDt(new Date());
job.setIsEnabled(true);
job.setIsCompleted(false);
JobContext context = new JobContext(beanFactory, scheduler, locator, job);
job.setQuartzGroup(context.getQuartzGroup());
job.setQuartzName(context.getQuartzName());
followJobRepository.save(job);
JobSchedulerUtil.schedule(new JobContext(beanFactory, scheduler, locator, job));
}
}
JobContext
我构建包含有关作业的详细信息,并最终传递给用于调度作业的实用程序。以下是实际调度作业的实用程序方法的代码。请注意,在我的服务中,我会自动装配JobScheduler
并将其传递给JobContext
。另请注意,我使用我的存储库将作业存储在数据库中。
/**
* Schedules a DATA_MINING_JOB for the client. The job will attempt to enter
* followers of the target into the database.
*/
@Override
public void schedule(JobContext context) {
Client client = context.getNetworkSociallyJob().getClient();
this.logScheduleAttempt(context, client);
JobDetail jobDetails = JobBuilder.newJob(this.getJobClass()).withIdentity(context.getQuartzName(), context.getQuartzGroup()).build();
jobDetails.getJobDataMap().put("job", context.getNetworkSociallyJob());
jobDetails.getJobDataMap().put("repositories", context.getRepositories());
Trigger trigger = TriggerBuilder.newTrigger().withIdentity(context.getQuartzName() + "-trigger", context.getQuartzGroup())
.withSchedule(cronSchedule(this.getSchedule())).build();
try {
context.getScheduler().scheduleJob(jobDetails, trigger);
this.logSuccess(context, client);
} catch (SchedulerException e) {
this.logFailure(context, client);
e.printStackTrace();
}
}
因此,在完成所有这些代码后,我发生了两件事,我的工作是存储在数据库中,并使用quartz调度程序进行调度。现在,如果应用程序重新启动,我想使用调度程序重新安排我的作业。为此,我注册了一个实现ApplicationListener<ContextRefreshedEvent>
的bean,每次容器重启或启动时都会被Spring调用。
<bean id="jobInitializer" class="com.network.socially.web.jobs.JobInitializer"/>
<强> JobInitializer.class 强>
public class JobInitializer implements ApplicationListener<ContextRefreshedEvent> {
Logger logger = LoggerFactory.getLogger(JobInitializer.class);
@Autowired
DataMiningJobRepository repository;
@Autowired
ApplicationJobRepository jobRepository;
@Autowired
Scheduler scheduler;
@Autowired
JobSchedulerLocator locator;
@Autowired
ListableBeanFactory beanFactory;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
logger.info("Job Initilizer started.");
//TODO: Modify this call to only pull completed & enabled jobs
for (ApplicationJob applicationJob : jobRepository.findAll()) {
if (applicationJob.getIsEnabled() && (applicationJob.getIsCompleted() == null || !applicationJob.getIsCompleted())) {
JobSchedulerUtil.schedule(new JobContext(beanFactory, scheduler, locator, applicationJob));
}
}
}
}
此类自动装配调度程序和存储库,该存储库用于获取实现ApplicationJob
接口的每个作业的实例。使用这些数据库记录中的信息,我可以使用我的调度程序实用程序来重建我的作业。
所以基本上我手动将作业存储在我的数据库中,并通过在适当的bean中注入Scheduler
的实例来手动调度它们。要重新安排它们,我会查询我的数据库,然后使用ApplicationListener
计划它们,以便重新启动和启动容器。
答案 1 :(得分:6)
我想有一些可用于Spring和Quartz JDBC作业存储集成的文档;例如: