Quartz()整合Spring容器中bean及動態調度任務

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


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章