问题描述
我对Quartz很新,现在我需要在Spring Web应用程序中安排一些工作。
I'm quite new to Quartz and now I need to schedule some jobs in Spring web application.
我知道Spring + Quartz集成(我正在使用Spring v 3.1.1)但我想知道这是否是正确的方法。
I know about Spring + Quartz integration (I'm using Spring v 3.1.1) but I'm wondering if this is the right way to follow.
特别是我需要坚持我的预定任务在数据库中,所以我可以在重新启动应用程序时重新初始化它们。
In particular I need to persist my scheduled tasks in a DB so I can re-initialize them when application is restarted.
Spring调度包装器是否提供了一些实用程序来执行此操作?
你能建议我采用一些众所周知的方法吗?
Are there some utilities provided by Spring scheduling wrapper to do this?Can you suggest me some "well known" approach to follow?
推荐答案
这是我处理这种情况的一种方法。
Here is one way I handle this scenario.
首先在我的Spring配置中指定一个 SchedulerFactoryBean
我可以从中注入调度程序
到其他bean中。
First in my Spring Configuration I specify a SchedulerFactoryBean
from which I can inject the Scheduler
into other beans.
<bean name="SchedulerFactory"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="applicationContextSchedulerContextKey">
<value>applicationContext</value>
</property>
</bean>
然后,当我在应用程序中创建作业时,我将作业的详细信息存储在数据库中。这个服务由我的一个控制器调用,它安排工作:
Then when I create a job in my application I store the details of the job in the database. This service is called by one of my controllers and it schedules the job:
@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
。另请注意,我使用我的存储库将作业存储在数据库中。
The JobContext
I build contains detail about the job and is eventually passed to a utility for scheduling jobs. Here is that code for the utility method that actually schedules the job. Notice that in my service I autowire the JobScheduler
and pass it to the JobContext
. Also notice that I store the job in the database using my repository.
/**
* 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调用。
So after all of this code executes I two things have happened, my job is store in the database and its been scheduled using the quartz scheduler. Now if the application restarts I want to reschedule my jobs with the scheduler. To do this I register a bean that implements ApplicationListener<ContextRefreshedEvent>
which is called by Spring each time the container restarts or is started.
<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
接口的每个作业的实例。使用这些数据库记录中的信息,我可以使用我的调度程序实用程序重建我的作业。
This class autowires the scheduler and a repository that grabs instances of each of my jobs that implement the ApplicationJob
interface. Using the information from these database records I can use my scheduler utility to reconstruct my jobs.
所以基本上我手动将作业存储在我的数据库中并通过注入一个来手动调度它们适当bean中的 Scheduler
的实例。要重新安排它们,我查询我的数据库,然后使用 ApplicationListener
安排它们来计算容器的重启和启动。
So basically I manually store the jobs in my database and manually schedule them by injecting a instance of the Scheduler
in appropriate beans. To rescheduled them, I query my database and then schedule them using the ApplicationListener
to account for restarts and starts of the container.
这篇关于在数据库中持久保存Quartz触发器的正确方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!