项目中经常会碰到需要定时执行的任务,并且需要执行什么任务,以及任务执行的时间都由用户自定义的需求。quartz是比较常用的定时器工具,并且在spring框架中也已经做了很好的集成,所以在以spring+hibernate+struts的主流架构中,我们可以采用quartz来做定时器任务的解决方案,下面,我们来看下如何在项目中使用quartz来做动态多任务定时器功能。
1.简单单任务定时器的spring配置
view plaincopy to clipboardprint?
<!-- 配置定时任务,用于初始化定时器 -->
<bean id="InitJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="ReportJobTodo"/>
</property>
<property name="targetMethod">
<value>initJobTrigger</value>
</property>
<property name="concurrent" value ="false"/>
</bean>
<bean id="ReportJobTodo"
class="cn.com.gsoft.report.timetask.ReportJobTodo">
</bean>
<bean id="InitTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="InitJobDetail"/>
</property>
<property name="cronExpression">
<value>* * * * * ?</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="InitTrigger"/>
</list>
</property>
</bean>
<!-- 配置定时任务,用于初始化定时器 -->
<bean id="InitJobDetail"
class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject">
<ref bean="ReportJobTodo"/>
</property>
<property name="targetMethod">
<value>initJobTrigger</value>
</property>
<property name="concurrent" value ="false"/>
</bean>
<bean id="ReportJobTodo"
class="cn.com.gsoft.report.timetask.ReportJobTodo">
</bean>
<bean id="InitTrigger"
class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail">
<ref bean="InitJobDetail"/>
</property>
<property name="cronExpression">
<value>* * * * * ?</value>
</property>
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref local="InitTrigger"/>
</list>
</property>
</bean>
说明:(1).InitJobDetail实例声明了需要执行的任务。其中targetObject说明了需要执行的方法所在的实例对象,targetMethod说明了要执行的方法,concurrent用于说明多个任务是否同步执行。
(2).InitTrigger声明了一个触发器。jobDetail属性指明需要执行的任务,cronExpression声明了该任务在什么时候执行,该表达式跟linux下的crontab定时程序中使用的表达式是一样的,具体使用方法可以参考文后的参考资料。
(3).SchedulerFactoryBean中可以定义多个触发器,以实现多任务。
2.动态多任务实现
实现方式:用户在前台自行维护任务列表和任务执行时间,后台将任务执行时间解析成对应的cronexpression后与任务列表一起保存到数据库中。在服务器运行期间添加的任务通过验证的(quartz会验证cronexpression是否合法以及对应时间是否已经过期)将直接添加一个任务以及触发器。如果服务器重启,在项目启动时读取配置文件执行一次任务初始化动作,保证通过验证的任务能在触发队列中,并在到达指定时间时能够触发执行。
(1).在applicationContext.xml中添加如1中的配置,配置的任务只执行一次后即被禁用,initJobTrigger方法如下:
view plaincopy to clipboardprint?
/**
* 容器启动时初始化任务
* @throws SchedulerException
* @throws ParseException
*/
public void initJobTrigger() throws SchedulerException, ParseException{
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//获取任务列表的HQL语句
String hql = "from ReportJob r where r.enabled = ?";
List list = baseDao.selectByHql(hql, new Object[]{ReportJobConstants.TRUE_STRING});
if(null != list && list.size() > 0){
Iterator ite = list.iterator();
while(ite.hasNext()){
//任务对象
ReportJob rj = (ReportJob)ite.next();
//定时表达式
String cronExpression = rj.getCronExpression();
//新建任务,任务组为默认的Scheduler.DEFAULT_GROUP,需要执行的任务类为ReportJobTodo.class
JobDetail jobDetail = new JobDetail("reportJob_" + rj.getGuId(), Scheduler.DEFAULT_GROUP,
ReportJobTodo.class);
//新建触发器,触发器为默认的Scheduler.DEFAULT_GROUP
CronTrigger cronTrigger = new CronTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
//为触发器设置定时表达式
cronTrigger.setCronExpression(cronExpression);
try{
//启动新增定时器任务
scheduler.scheduleJob(jobDetail, cronTrigger);
}catch(SchedulerException e){
//启动验证失败,设置任务标记为禁用
e.printStackTrace();
rj.setEnabled(ReportJobConstants.FALSE_STRING);
baseDao.updateObject(rj);
}
}
}
//初始化任务只需要执行一次,执行一次后移除初始化触发器
scheduler.unscheduleJob("InitTrigger", Scheduler.DEFAULT_GROUP);
//任务启动
scheduler.start();
}
/**
* 容器启动时初始化任务
* @throws SchedulerException
* @throws ParseException
*/
public void initJobTrigger() throws SchedulerException, ParseException{
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//获取任务列表的HQL语句
String hql = "from ReportJob r where r.enabled = ?";
List list = baseDao.selectByHql(hql, new Object[]{ReportJobConstants.TRUE_STRING});
if(null != list && list.size() > 0){
Iterator ite = list.iterator();
while(ite.hasNext()){
//任务对象
ReportJob rj = (ReportJob)ite.next();
//定时表达式
String cronExpression = rj.getCronExpression();
//新建任务,任务组为默认的Scheduler.DEFAULT_GROUP,需要执行的任务类为ReportJobTodo.class
JobDetail jobDetail = new JobDetail("reportJob_" + rj.getGuId(), Scheduler.DEFAULT_GROUP,
ReportJobTodo.class);
//新建触发器,触发器为默认的Scheduler.DEFAULT_GROUP
CronTrigger cronTrigger = new CronTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
//为触发器设置定时表达式
cronTrigger.setCronExpression(cronExpression);
try{
//启动新增定时器任务
scheduler.scheduleJob(jobDetail, cronTrigger);
}catch(SchedulerException e){
//启动验证失败,设置任务标记为禁用
e.printStackTrace();
rj.setEnabled(ReportJobConstants.FALSE_STRING);
baseDao.updateObject(rj);
}
}
}
//初始化任务只需要执行一次,执行一次后移除初始化触发器
scheduler.unscheduleJob("InitTrigger", Scheduler.DEFAULT_GROUP);
//任务启动
scheduler.start();
}
(2).所有的触发器执行的任务类均为ReportJobTodo.class,ReportJobTodo需要实现接口:org.quartz.Job中的方法execute方法,参考代码如下:
view plaincopy to clipboardprint?
/**
* 报表生成任务
*/
public void execute(JobExecutionContext je) throws JobExecutionException {
//获取触发器名称
String triggerName = je.getTrigger().getName();
//根据触发器名称得到对应的任务Id
Long reportJobGuId = Long.valueOf(triggerName.split("_")[1]);
//获取任务
ReportJob rj = (ReportJob)baseDao.loadObject(ReportJob.class, reportJobGuId);
//获取任务细节列表
String hql = "from ReportJobDetail t where reportJobGuId = ?";
List list = baseDao.selectByHql(hql, new Object[]{reportJobGuId});
if(null != list && list.size() > 0){
Iterator ite = list.iterator();
while(ite.hasNext()){
//任务细节对象
ReportJobDetail rjd = (ReportJobDetail)ite.next();
//根据获取的任务对象来做具体操作
//something to do
}
}
//如果有需要,可以将执行过的任务移除
//try {
// je.getScheduler().unscheduleJob(triggerName, je.getTrigger().getGroup());
//} catch (SchedulerException e) {
// throw new BusinessException(e.getMessage());
//}
}
/**
* 报表生成任务
*/
public void execute(JobExecutionContext je) throws JobExecutionException {
//获取触发器名称
String triggerName = je.getTrigger().getName();
//根据触发器名称得到对应的任务Id
Long reportJobGuId = Long.valueOf(triggerName.split("_")[1]);
//获取任务
ReportJob rj = (ReportJob)baseDao.loadObject(ReportJob.class, reportJobGuId);
//获取任务细节列表
String hql = "from ReportJobDetail t where reportJobGuId = ?";
List list = baseDao.selectByHql(hql, new Object[]{reportJobGuId});
if(null != list && list.size() > 0){
Iterator ite = list.iterator();
while(ite.hasNext()){
//任务细节对象
ReportJobDetail rjd = (ReportJobDetail)ite.next();
//根据获取的任务对象来做具体操作
//something to do
}
}
//如果有需要,可以将执行过的任务移除
//try {
// je.getScheduler().unscheduleJob(triggerName, je.getTrigger().getGroup());
//} catch (SchedulerException e) {
// throw new BusinessException(e.getMessage());
//}
}
(3).对于每一个任务提供启用和禁用的功能,启用时将任务加入到任务执行列表中,禁用时移除:
view plaincopy to clipboardprint?
/**
* 启动或禁止任务触发器
* @param condition
* @throws SchedulerException
* @throws ParseException
*/
public static void enableTrigger(ReportJobCondition condition) throws SchedulerException, ParseException{
//获取任务对象的HQL语句
String hql = "from ReportJob t where t.guId = ?";
List list = dao.selectByHql(hql, new Object[]{condition.getObjGuId()});
if(null != list && list.size() > 0){
//任务对象
ReportJob rj = (ReportJob)list.get(0);
//定时器表达式
String cronExpression = rj.getCronExpression();
//获取调度工厂对象
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//启动任务
if(ReportJobConstants.TRUE_STRING.equals(condition.getEnabled())){
//添加任务
JobDetail jobDetail = new JobDetail("reportJob_" + rj.getGuId(), Scheduler.DEFAULT_GROUP,
ReportJobTodo.class);
//添加触发器
CronTrigger cronTrigger = new CronTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
//设置定时表达式
cronTrigger.setCronExpression(cronExpression);
//启动任务
scheduler.scheduleJob(jobDetail, cronTrigger);
rj.setEnabled(ReportJobConstants.TRUE_STRING);
dao.updateObject(rj);
dao.flush();
}else{
//移除触发器
CronTrigger cronTrigger = (CronTrigger)scheduler.getTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
if(null != cronTrigger){
scheduler.unscheduleJob(cronTrigger.getName(), Scheduler.DEFAULT_GROUP);
}
rj.setEnabled(ReportJobConstants.FALSE_STRING);
dao.updateObject(rj);
dao.flush();
}
//调度器启动
scheduler.start();
}
}
/**
* 启动或禁止任务触发器
* @param condition
* @throws SchedulerException
* @throws ParseException
*/
public static void enableTrigger(ReportJobCondition condition) throws SchedulerException, ParseException{
//获取任务对象的HQL语句
String hql = "from ReportJob t where t.guId = ?";
List list = dao.selectByHql(hql, new Object[]{condition.getObjGuId()});
if(null != list && list.size() > 0){
//任务对象
ReportJob rj = (ReportJob)list.get(0);
//定时器表达式
String cronExpression = rj.getCronExpression();
//获取调度工厂对象
SchedulerFactory schedulerFactory = new StdSchedulerFactory();
Scheduler scheduler = schedulerFactory.getScheduler();
//启动任务
if(ReportJobConstants.TRUE_STRING.equals(condition.getEnabled())){
//添加任务
JobDetail jobDetail = new JobDetail("reportJob_" + rj.getGuId(), Scheduler.DEFAULT_GROUP,
ReportJobTodo.class);
//添加触发器
CronTrigger cronTrigger = new CronTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
//设置定时表达式
cronTrigger.setCronExpression(cronExpression);
//启动任务
scheduler.scheduleJob(jobDetail, cronTrigger);
rj.setEnabled(ReportJobConstants.TRUE_STRING);
dao.updateObject(rj);
dao.flush();
}else{
//移除触发器
CronTrigger cronTrigger = (CronTrigger)scheduler.getTrigger("trigger_" + rj.getGuId(), Scheduler.DEFAULT_GROUP);
if(null != cronTrigger){
scheduler.unscheduleJob(cronTrigger.getName(), Scheduler.DEFAULT_GROUP);
}
rj.setEnabled(ReportJobConstants.FALSE_STRING);
dao.updateObject(rj);
dao.flush();
}
//调度器启动
scheduler.start();
}
}
参考资料:
1.cronExpression介绍:http://en.wikipedia.org/wiki/CRON_expression
http://jlusdy.javaeye.com/blog/87044
2.quartz官方文档:http://www.quartz-scheduler.org/docs/index.html
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/rebsto/archive/2010/10/05/5922834.aspx