轉自: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