转自:http://www.myexception.cn/software-architecture-design/838095.html(我的异常网-MY Exception)
此文档中有几个类(用百度也搜不到)是自己写的,(关于用到的quartz文档和数据库,我在我的博客资源上传的有,用到可以进行下载)
还可以结合这个链接看看:http://mengqingyu.iteye.com/blog/568935
Quartz(二)整合Spring容器中bean及动态调度任务
Quartz 是开源任务调度框架中的翘首,它提供了强大任务调度机制,同时保持了使用的简单性。Quartz 允许开发人员灵活地定义触发器的调度时间表,并可以对触发器和任务进行关联映射。
此外,Quartz提供了调度运行环境的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失。
此外,Quartz还提供了组件式的侦听器、各种插件、线程池等功能。
Spring中使用Quartz的3种方法(MethodInvokingJobDetailFactoryBean,implements Job,extends QuartzJobBean)
以下介绍一下实现job接口的方法,通过此方法可以动态启动,暂定,添加,删除定时功能,可传参数。
所有数据全部持久化到数据表中,不再需要XML配置文件存储数据。quartz已经封装了持久化方法。数据表用的MYSQL见附件
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.webframe.web.springmvc.bean.AjaxError;
import org.webframe.web.springmvc.exp.AjaxException;
import com.berheley.bi.basic.constant.BIConstant;
import com.berheley.bi.basic.core.JtaBaseService;
import com.berheley.bi.basic.util.UUIDGenerator;
//对定时任务增删改
@Service
public class TimerService extends JtaBaseService implements ITimerService,ITimerJob {
private static final Log log = LogFactory.getLog(TimerService.class);
@Autowired
private Scheduler scheduler;
@Override
public void updateExecuteBatch(Map<String, Object> object, String[] formId) {
String typeName = (String) object.get("typeName");
String[] sql = new String[formId.length];
for (int i = 0; i < formId.length; i++) {
sql[i] = "update dic_table_diction set SET_DS_TIME_='" + typeName + "' where ID_='" + formId[i] + "';";
}
try {
super.getJtaCoreDao().doBatchInsert(sql);
} catch (Exception e) {
createAjaxException("定时发布到mysql中的t_table_inf表发生异常", e);
}
}
@Override
public void addTimer(Map<String, Object> params, JobDetail jobDetail) throws Exception {
String month = params.get("month").toString();
String day = params.get("day").toString();
String type = params.get("formType").toString();// 报表类型
String typeName;
String cronExpression;
if (type.equals("1")) {
typeName = "每年" + month + "月" + day + "日";
cronExpression = "0 0 0 " + day + " " + month + " ?";
} else if (type.equals("3")) {
typeName = "每月" + day + "日";
cronExpression = "0 1 0 " + day + " * ?";
} else if (type.equals("4")) {
typeName = "每周" + day;
cronExpression = "0 2 0 ? * " + day;
} else {
typeName = "每日";
cronExpression = "0 3 0 * * ?";
}
params.put(BIConstant.Constant_ID_, UUIDGenerator.getUUID());
params.put("typeName", typeName);
String[] formId = params.get("formIds").toString().split(",");
this.updateExecuteBatch(params, formId);// 更新diction表
Map<String, String> jobParams = new HashMap<String, String>();
for (int i = 0; i < formId.length; i++) {
jobDetail.setName(formId[i]);
this.deleteTimer(jobDetail.getName(), jobDetail.getGroup());// 清空定时任务
jobParams.put("beanName", "timerService");
jobParams.put("formId", jobDetail.getName());
jobParams.put("CHECK_STATUS_", params.get("CHECK_STATUS_").toString());
jobParams.put("START_TIME_", params.get("START_TIME_").toString());
jobParams.put("END_TIME_", params.get("END_TIME_").toString());
this.saveTimer(jobParams, jobDetail);// 添加定时任务
this.saveCron(jobDetail.getName(), jobDetail.getGroup(), formId[i], formId[i], cronExpression);// 设置定时时间
}
}
@Override
public void saveTimer(Map<String, String> jobParams, JobDetail jobDetail) throws SchedulerException,
ClassNotFoundException {
for (String s : jobParams.keySet()) {
jobDetail.getJobDataMap().put(s, jobParams.get(s));
}
scheduler.addJob(jobDetail, true);
}
@Override
public void saveCron(String jobName, String jobGroup, String triggerName, String triggerGroup, String cronExpression)
throws SchedulerException, ParseException {
CronTrigger trigger = new CronTrigger(triggerName, triggerGroup, jobName, jobGroup, cronExpression);
trigger.setVolatility(false);
scheduler.scheduleJob(trigger);
}
@Override
public void deleteTimer(String jobName, String jobGroup) throws SchedulerException {
JobDetail jobDetail = scheduler.getJobDetail(jobName, jobGroup);
if (jobDetail != null) {
scheduler.deleteJob(jobName, "DEFAULT");
}
}
@Override
public void addRunNowTimer(String jobName, String jobGroup) throws SchedulerException {
scheduler.triggerJob(jobName, jobGroup);
}
@Override
public void updatePauseTrigger(String triggerName, String group) throws SchedulerException {
scheduler.pauseTrigger(triggerName, group);// 停止触发器
}
@Override
public void updateResumeTrigger(String triggerName, String group) throws SchedulerException {
scheduler.resumeTrigger(triggerName, group);// 重启触发器
}
@Override
public boolean removeTrigdger(String triggerName, String group) throws SchedulerException {
scheduler.pauseTrigger(triggerName, group);// 停止触发器
return scheduler.unscheduleJob(triggerName, group);// 移除触发器
}
/*
* 定时操作,先查询数据(dic_table_diction,t_table_assgin),然后向t_table_inf插入记录,并向oracle插入数据
* @see com.berheley.bi.service.def.TimerService#jtaTimerDataJob(org.quartz.JobExecutionContext)
*/
@Override
public void jtaTimerExecute(JobExecutionContext context) {
Map<String, Object> parameters = context.getJobDetail().getJobDataMap();
System.out.println(formName + "\t----------定时发布完成-----------");
}
}
import java.text.ParseException;
import java.util.List;
import java.util.Map;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;
public interface ITimerService
{
/**
* 批量修改数据
* @param object
*/
public void updateExecuteBatch(Map<String,Object> object,String[] formId);
/**
* 设置定时功能
* @param request
* @param jdetail
*/
void addTimer(Map<String, Object> params,JobDetail jobDetail)throws Exception;
/**
* 添加定时任务
* @param request
* @param parameterNames
* @param parameterValues
* @param parameterValues
*/
void saveTimer(Map<String,String> jobParams,JobDetail jobDetail) throws SchedulerException, ClassNotFoundException ;
/**
* 设置定时时间
* @param request
* @param jobName
* @param jobGroup
* @param triggerName
* @param triggerGroup
* @param cronExpression
*/
void saveCron(String jobName,String jobGroup,String triggerName,String triggerGroup,String cronExpression) throws SchedulerException, ParseException;
/**
* 删除定时器
* @param request
* @param jobName
* @param jobGroup
*/
void deleteTimer(String jobName,String jobGroup) throws SchedulerException;
/**
* 立即执行定时功能
* @param request
* @param jobName
* @param jobGroup
*/
void addRunNowTimer(String jobName,String jobGroup) throws SchedulerException;
/**
* 根据名称和组别暂停Tigger
* @param triggerName
* @param group
*/
void updatePauseTrigger(String triggerName,String group) throws SchedulerException;
/**
* 恢复Trigger
* @param triggerName
* @param group
*/
void updateResumeTrigger(String triggerName,String group) throws SchedulerException;
/**
* 删除Trigger
* @param triggerName
* @param group
*/
boolean removeTrigdger(String triggerName,String group) throws SchedulerException;
}
import org.quartz.JobExecutionContext;
//定时调度执行方法,便于扩展
public interface ITimerJob
{
/**
* 定时器执行的任务
* @param context
* @throws Exception
*/
public void jtaTimerExecute(JobExecutionContext context) throws Exception;
}
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
<span style="color:#ff6666;">import org.webframe.web.util.WebFrameUtils;</span>
//定时调度执行类
public class TimerDataJob implements Job
{
private ITimerJob timerJob;
@Override
public void execute(JobExecutionContext context)
throws JobExecutionException
{
timerJob = (ITimerJob)<span style="color:#ff6666;">WebFrameUtils</span>
.getBean(context.getJobDetail().getJobDataMap().get("beanName").toString());//通过保存的bean参数来获取对应的bean要求必须实现ITimerJob接口
try{
timerJob.jtaTimerExecute(context);
} catch (Exception e){
e.printStackTrace();
}
}
}
这种配置就是对quartz的一种简单的使用了,调度任务会在spring启动的时候加载到内存中,按照bjcronTrigger中定义的crontrigger定义的时间按时触发调度任务。
但是这是quartz使用“内存”方式的一种配置,也比较常见,当然对于不使用spring的项目,也可以单独整合quartz。
方法也比较简单,可以从quartz的doc中找到配置方式,或者看一下《Quartz Job Scheduling Framework 》(附件中可下载)这本书中的例子。
但是对于想持久化调度任务的状态,并且灵活调整调度时间的方式来说,上面的内存方式就不能满足要求了,正如本文开始我遇到的情况,需要采用数据库方式集成quartz,
这部分集成其实在《Quartz Job Scheduling Framework 》中也有较为详细的介绍,当然doc文档中也有,
但是缺乏和spring集成的实例,我在这里把我在项目中在spring配置quartz数据库存储方式的配置也写一下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <bean name="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="dataSource"> <ref bean="dataSource" /> </property> <property name="applicationContextSchedulerContextKey" value="BI-Scheduler" /> <property name="configLocation" value="classpath:quartz.properties" /> </bean> </beans>
属性说明:
dataSource:项目中用到的数据源,里面包含了quartz用到的12张数据库表;
schedulerName:调度器名,我理解主要在调度集群的时候会有用,如果出现多个调度器实例的时候可以用来进行区分,详细看一下《Quartz Job Scheduling Framework 》;
configLocation:用于指明quartz的配置文件的位置,如果不用spring配置quartz的话,本身quartz是通过一个配置文件进行配置的
,默认名称是quartz.properties,里面配置的参数在quartz的doc文档中都有介绍,可以调整quartz,我在项目中也用这个文件部分的配置了一些属性,代码如下:
#============================================================================ # Configure Main Scheduler Properties #============================================================================ org.quartz.scheduler.instanceName = TestScheduler org.quartz.scheduler.instanceId = AUTO #============================================================================ # Configure ThreadPool #============================================================================ org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 5 org.quartz.threadPool.threadPriority = 4 #============================================================================ # Configure JobStore #============================================================================ org.quartz.jobStore.misfireThreshold = 60000 #org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX ##org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.OracleDelegate #org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate #org.quartz.jobStore.dataSource = myDS org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.isClustered = false #============================================================================ # Configure Plugins #============================================================================ org.quartz.plugin.triggHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin #org.quartz.plugin.jobInitializer.class = org.quartz.plugins.xml.JobInitializationPlugin # init plugin will load jobs.xml as a classpath resource i.e. /jobs.xml if not found on file system #org.quartz.plugin.jobInitializer.fileName=jobs.xml #org.quartz.plugin.jobInitializer.overWriteExistingJobs = false #org.quartz.plugin.jobInitializer.failOnFileNotFound = false