Quartz是当前非常流行的定时任务调度框架,个人认为比Java 7中的Timer好用。重点在于,它可以很好的和Spring框架进行整合,实现更强大的功能。最近写了一个小功能涉及Spring整合Quartz实现任务动态调度,摘取代码片段分享在这里,供参考。
实现的比较简单,主要分如下几步:
1.在spring配置文件中配置Quartz的调度器
<bean id="schedulerFactory" lazy-init="true" autowire="no"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
</bean>
2.在想要进行调度的代码片段,通过获取当前ApplicationContext拿到调度器
//获取spring里的调度器
StdScheduler scheduler = (StdScheduler) ContextLoader.getCurrentWebApplicationContext().getBean("schedulerFactory");
3.然后进行触发器和作业的分配,其中MovieTask即要调度的作业
JobDetail jobDetail= null;
TriggerBuilder<Trigger> triggerBuilder = null;
CronTrigger trigger = null;
for (int i = 0; i < totalNum; i++) {
//声明任务对象[任务组,任务执行类]
jobDetail= JobBuilder.newJob(MovieTask.class).build();
jobDetail.getJobDataMap().put("movieName", movieNameList.get(i));//这里是传入的参数
//触发器配置[Cron表达式]
triggerBuilder = TriggerBuilder.newTrigger();
triggerBuilder.startNow();
triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(CronUtils.getRandomCronStr(date)));
//声明触发器对象
trigger = (CronTrigger)triggerBuilder.build();
//调度容器调度JobDetail和Trigger
scheduler.scheduleJob(jobDetail,trigger);
}
4.这里可以搞一个工具类,用于将date转换为cron表达式(因为需求需要,我生成的cron表达式中秒数是随机生成的)。
public static String getRandomCronStr(Date date)throws Exception{
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
long senconds = Math.round(Math.random()*(58)+1);
String cronStr = senconds+" "
+calendar.get(Calendar.MINUTE)+" "
//+Math.round(Math.random()*(58)+1)+" "
+calendar.get(Calendar.HOUR_OF_DAY)+" "
+calendar.get(Calendar.DATE)+" "
+(calendar.get(Calendar.MONTH)+1)+" ? " //Calendar的月份比实际少1
+calendar.get(Calendar.YEAR)+" ";
return cronStr;
}
5.MovieTask代码
public class MovieTask implements Job{
private static transient Logger log = Logger.getLogger(MovieTask.class);
@Override
public void execute(JobExecutionContext jobexecutioncontext) throws JobExecutionException {
String movieName = jobexecutioncontext.getJobDetail().getJobDataMap().get("movieName").toString();
}
}
完成以上几步,quartz动态调度基本功能就实现了。几点说明:
1.本例生成的是立即执行(cron表达式写死了执行时间)的作业,执行完毕后会自动从调度器中删除,无需手动删除;
2.对于立即执行的作业,cron表达式的实行时间一定要晚于当前时间,否则会抛出异常;
3.被调度的作业一定要实现Job接口;
4.关于作业持久化问题。quartz官方做法是在数据库中新建10张表实现的,个人觉得配置比较麻烦。在需求不是很复杂的前提下(其实大多数需要动态配置的作业都是立即执行的),可以考虑采用上面的思路实现。比如数据库建一张作业配置表(关键字段:作业classPath,cron表达式,作业状态),启一个每分钟执行一次的作业去扫这张表,扫到后添加到调度器中,然后将数据库的记录移到历史表;
5.以上解决方案都是基于单机应用实现的,如果是集群情况需要另行处理。