Quartz(二)整合Spring容器中bean及动态调度任务

Quartz 是开源任务调度框架中的翘首,它提供了强大任务调度机制,同时保持了使用的简单性。
Quartz 允许开发人员灵活地定义触发器的调度时间表,并可以对触发器和任务进行关联映射。
此外,Quartz提供了调度运行环境的持久化机制,可以保存并恢复调度现场,即使系统因故障关闭,任务调度现场数据并不会丢失。
此外,Quartz还提供了组件式的侦听器、各种插件、线程池等功能。

Spring中使用Quartz的3种方法(MethodInvokingJobDetailFactoryBean,implements Job,extends QuartzJobBean)
以下介绍一下实现job接口的方法,通过此方法可以动态启动,暂定,添加,删除定时功能,可传参数。
所有数据全部持久化到数据表中,不再需要XML配置文件存储数据。quartz已经封装了持久化方法。数据表用的MYSQL见附件


package com.berheley.bi.basic.timer;

import java.util.Map;

import org.quartz.JobExecutionContext;

import com.berheley.bi.basic.exp.BusinessException;

/**
 * 类功能描述:定时任务需要实现此接口
 *
 * @author      <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * Create:      2010-1-3 上午09:18:51
 * Description: 
 */
public interface ITimerJob
{
	/**
	 * 定时器执行的任务
	 * @param context
	 * @throws Exception 
	 */
	void jtaTimerExecute(JobExecutionContext context, Map<?, ?> parameters)throws BusinessException;
}



package com.berheley.bi.basic.timer;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.webframe.web.util.WebFrameUtils;

import com.berheley.bi.basic.exp.BusinessException;

/**
 * 类功能描述:定时执行的任务,发布表单
 *
 * @author      <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * Create:      2009-12-31 上午12:31:02
 * Description: 
 */
public class TimerDataJob implements Job {

	private ITimerJob	timerJob;

	protected Log		log	= LogFactory.getLog(getClass());

	@Override
	public void execute(JobExecutionContext context) throws JobExecutionException {
		JobDataMap parameters = context.getJobDetail().getJobDataMap();
		try {
			Object beanName = parameters.get("beanName");
			if (beanName == null) {
				log.error("JobDataMap 中'beanName'属性值为null!");
				return;
			}
			timerJob = (ITimerJob) WebFrameUtils.getBean(beanName.toString());
			timerJob.jtaTimerExecute(context, parameters);
		} catch (NoSuchBeanDefinitionException e) {
			log.error("任务ITimerJob接口的实现类(" + e.getBeanName() + ")不存在!");
		} catch (BusinessException e) {
			log.error(e.getMessage(), e);
		}
	}
}


import java.util.Map;

import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.Trigger;

import com.berheley.bi.basic.exp.BusinessException;

/**
 * 类功能描述:定时调度后台管理
 * 
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a> Create: 2010-1-3 上午09:18:51
 *         Description:
 */
public interface ITimerManageService {

	/**
	 * 获得scheduler
	 */
	Scheduler getScheduler();
	/**
	 * 
	 * @function:获得任务
	 * @param jobName
	 * @param jobGroup
	 * @return
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:29:03
	 */
	JobDetail getJob(String jobName, String jobGroup) throws BusinessException;
	
	/**
	 * 
	 * @function:添加任务
	 * @param jobDetail
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:29:15
	 */
	void addJob(JobDetail jobDetail) throws BusinessException;
	
	/**
	 * 
	 * @function:删除任务
	 * @param jobName
	 * @param jobGroup
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:29:31
	 */
	void deleteJob(String jobName, String jobGroup) throws BusinessException;
	
	/**
	 * 
	 * @function:立即运行
	 * @param jobName
	 * @param jobGroup
	 * @author: mengqingyu    2012-5-24 上午11:00:20
	 */
	void addRunNowTrigger(String jobName, String jobGroup) throws BusinessException ;

	/**
	 * 
	 * @function:重置定时器
	 * @param jobName
	 * @param jobGroup
	 * @param trigger
	 * @throws BusinessException
	 * @author: mengqingyu    2012-11-30 下午05:22:48
	 */
	public void rescheduleJob(String triggerName, String triggerGroup, Trigger trigger) throws BusinessException;
	
	/**
	 * 
	 * @function:获得定时器
	 * @param jobName
	 * @param jobGroup
	 * @return
	 * @throws BusinessException
	 * @author: mengqingyu    2012-11-30 下午05:17:09
	 */
	Trigger getTrigger(String jobName, String jobGroup) throws BusinessException;
	
	/**
	 * 
	 * @function:添加定时
	 * @param trigger
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:29:41
	 */
	void addTrigger(Trigger trigger) throws BusinessException;
	
	/**
	 * 删除定时
	 * 
	 * @param triggerName
	 * @param group
	 */
	void deleteTrigger(String triggerName, String group) throws BusinessException ;
	
	/**
	 * 暂停定时
	 * 
	 * @param triggerName
	 * @param group
	 */
	void updatePauseTrigger(String triggerName, String group) throws BusinessException ;

	/**
	 * 恢复Trigger
	 * 
	 * @param triggerName
	 * @param group
	 */
	void updateResumeTrigger(String triggerName, String group) throws BusinessException ;

	/**
	 * 
	 * @function:保存、修改任务
	 * @param jobName
	 * @param jobGroup
	 * @param description
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:32:35
	 */
	void saveOrUpdateJob(String jobName, String jobGroup, String description) throws BusinessException;
	
	/**
	 * 
	 * @function:批量删除任务
	 * @param jobNames
	 * @param jobGroup
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:33:11
	 */
	void deleteJobs(String jobNames, String jobGroup) throws BusinessException;
	
	/**
	 * 
	 * @function:查询任务参数
	 * @param jobName
	 * @param jobGroup
	 * @return
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:34:20
	 */
	String findJobParams(String jobName, String jobGroup) throws BusinessException;
	
	/**
	 * 
	 * @function:保存任务参数
	 * @param jobName
	 * @param jobGroup
	 * @param key
	 * @param value
	 * @return
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:38:17
	 */
	String saveJobParam(String jobName, String jobGroup, String key, String value) throws BusinessException;
	
	/**
	 * 
	 * @function:删除任务参数
	 * @param jobName
	 * @param jobGroup
	 * @param keys
	 * @return
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:38:26
	 */
	String deleteJobParams(String jobName, String jobGroup, String keys) throws BusinessException;
	
	/**
	 * 
	 * @function:保存cron
	 * @param params
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:38:41
	 */
	void saveCron(Map<String, Object> params) throws BusinessException;
	
	/**
	 * 
	 * @function:保存simple
	 * @param params
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:40:39
	 */
	void saveSimple(Map<String, Object> params) throws BusinessException;
	
	/**
	 * 
	 * @function:批量删除定时
	 * @param jobName
	 * @param group
	 * @param triggerNames
	 * @throws BusinessException
	 * @author: mengqingyu    2012-10-22 下午03:41:42
	 */
	void deleteTriggers(String jobName, String group, String triggerNames) throws BusinessException;
	
	/**
	 * 根据名称和组别启动和暂停Tigger
	 * 
	 * @param triggerName
	 * @param group
	 */
	String updateStartOrStop(String jobName, String jobGroup) throws BusinessException ;
}


import java.text.ParseException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import org.apache.commons.lang.StringUtils;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.webframe.core.util.DateUtils;

import com.berheley.bi.basic.exp.BusinessException;
import com.berheley.bi.basic.util.UUIDGenerator;

/**
 * 类功能描述:通用定时功能
 * 
 * @author <a href="mailto:qingyu.meng21@gmail.com">mengqingyu </a>
 * @version $Id: codetemplates.xml,v 1.1 2009/03/06 01:13:01 mengqingyu Exp $ Create: 2011-6-1
 *          下午05:03:06
 */
@Service
public class TimerManageService implements ITimerManageService {

	@Autowired
	protected Scheduler	scheduler;
	
	public Scheduler getScheduler() {
		return scheduler;
	}
	
	@Override
	public JobDetail getJob(String jobName, String jobGroup) throws BusinessException{
		JobDetail jobDetail;
		try {
			jobDetail = scheduler.getJobDetail(jobName, jobGroup);
		} catch (SchedulerException e) {
			throw new BusinessException("获取任务失败", e);
		}
		return jobDetail;
	}
	
	@Override
	public void addJob(JobDetail jobDetail) throws BusinessException{
		try {
			scheduler.addJob(jobDetail, true);
		} catch (SchedulerException e) {
			throw new BusinessException("添加任务失败", e);
		}
	}
	
	@Override
	public void deleteJob(String jobName, String jobGroup) throws BusinessException{
		try {
			scheduler.deleteJob(jobName, jobGroup);
		} catch (SchedulerException e) {
			throw new BusinessException("删除任务失败", e);
		}
	}
	
	@Override
	public void addRunNowTrigger(String jobName, String jobGroup) throws BusinessException{
		try {
			scheduler.triggerJob(jobName, jobGroup);
		} catch (SchedulerException e) {
			throw new BusinessException("立即运行任务失败", e);
		}
	}

	@Override
	public void rescheduleJob(String triggerName, String triggerGroup, Trigger trigger) throws BusinessException{
		try {
			scheduler.rescheduleJob(triggerName,triggerGroup,trigger);
		} catch (SchedulerException e) {
			throw new BusinessException("重置定时器失败", e);
		}
	}
	
	@Override
	public Trigger getTrigger(String triggerName, String triggerGroup) throws BusinessException{
		Trigger trigger;
		try {
			trigger = scheduler.getTrigger(triggerName,triggerGroup);
		} catch (SchedulerException e) {
			throw new BusinessException("获取定时器失败", e);
		}
		return trigger;
	}
	
	@Override
	public void addTrigger(Trigger trigger) throws BusinessException {
		try {
			trigger.setVolatility(false);
			scheduler.scheduleJob(trigger);
		} catch (SchedulerException e) {
			throw new BusinessException("添加定时器失败", e);
		}
	}
	
	@Override
	public void deleteTrigger(String triggerName, String group) throws BusinessException{
		this.updatePauseTrigger(triggerName, group);
		try {
			scheduler.unscheduleJob(triggerName, group);
		} catch (SchedulerException e) {
			throw new BusinessException("删除定时任务失败", e);
		}
	}
	
	@Override
	public void updatePauseTrigger(String triggerName, String group) throws BusinessException{
		try {
			scheduler.pauseTrigger(triggerName, group);
		} catch (SchedulerException e) {
			throw new BusinessException("停止定时任务失败", e);
		}
	}

	@Override
	public void updateResumeTrigger(String triggerName, String group) throws BusinessException{
		try {
			scheduler.resumeTrigger(triggerName, group);
		} catch (SchedulerException e) {
			throw new BusinessException("恢复定时任务失败", e);
		}
	}
	
	@Override
	public void saveOrUpdateJob(String jobName, String jobGroup, String description) throws BusinessException {
		JobDetail jobDetail;
		if(StringUtils.isBlank(jobName)){
			jobName = UUIDGenerator.getUUID();
			try {
				jobDetail = new JobDetail(jobName, jobGroup, Class.forName("com.berheley.bi.basic.timer.TimerDataJob"));
			} catch (ClassNotFoundException e) {
				throw new BusinessException("添加修改任务失败", e);
			}
		}
		else {
			jobDetail = this.getJob(jobName, jobGroup);
		}
		jobDetail.setDescription(description);
		this.addJob(jobDetail);
	}
	
	@Override
	public void deleteJobs(String jobNames, String group) throws BusinessException {
		String[] jobs = jobNames.split(",");
		String[] groups = group.split(",");
		for(int i=0;i<jobs.length;i++){
			this.deleteJob(jobs[i], groups[i]);
		}
	}
	
	public String paramMapToList(JobDataMap params) {
		ArrayList<List<String>> listJobData = new ArrayList<List<String>>();
		for (Object e: params.entrySet()) {
			Map.Entry<?, ?> entry = (Entry<?, ?>) e;
			ArrayList<String> list = new ArrayList<String>();
			list.add("'" + entry.getKey() + "'");
			list.add("'" + entry.getValue() + "'");
			listJobData.add(list);
		}
		return listJobData.toString();
	}
	
	@Override
	public String findJobParams(String jobName, String jobGroup) throws BusinessException {
		JobDetail jobDetail = this.getJob(jobName, jobGroup);
		return jobDetail == null?"{}":paramMapToList(jobDetail.getJobDataMap());
	}
	
	@Override
	public String saveJobParam(String jobName, String jobGroup, String key, String value) throws BusinessException {
		JobDetail jobDetail = this.getJob(jobName, jobGroup);
		JobDataMap params = jobDetail.getJobDataMap();
		params.put(key, value);
		this.addJob(jobDetail);
		return paramMapToList(params);
	}
	
	@Override
	public String deleteJobParams(String jobName, String jobGroup, String keys) throws BusinessException {
		JobDetail jobDetail = this.getJob(jobName, jobGroup);
		JobDataMap params = jobDetail.getJobDataMap();
		String[] key = keys.split(",");
		for(int i=0;i<key.length;i++){
			params.remove(key[i]);
		}
		this.addJob(jobDetail);
		return paramMapToList(params);
	}

	public void initTrigger(Trigger trigger, Map<String, Object> params) {
		trigger.setDescription(params.get("label").toString());
		trigger.setJobName(params.get("jobName").toString());
		trigger.setJobGroup(params.get("group").toString());
		String startTime = params.get("startTime")==null?"":params.get("startTime").toString();
		String stopTime = params.get("stopTime")==null?"":params.get("stopTime").toString();
		if (!StringUtils.isBlank(startTime)) {
			trigger.setStartTime(DateUtils.parseStringToDate(startTime,"yyyy-MM-dd HH:mm:ss"));
		}
		if (!StringUtils.isBlank(stopTime)) {
			trigger.setEndTime(DateUtils.parseStringToDate(stopTime,"yyyy-MM-dd HH:mm:ss"));
		}
	}
	
	@Override
	public void saveCron(Map<String, Object> params) throws BusinessException {
		Trigger trigger = null;
		try {
			trigger = new CronTrigger(UUIDGenerator.getUUID(), params.get("group").toString(), params.get("cronExpression").toString());
		} catch (ParseException e) {
			throw new BusinessException("添加cron失败", e);
		}
		this.initTrigger(trigger, params);
		this.addTrigger(trigger);
	}
	
	@Override
	public void saveSimple(Map<String, Object> params) throws BusinessException {
		String countStr = params.get("repeatCount").toString();
		int repeatCount = countStr.equals("")?SimpleTrigger.REPEAT_INDEFINITELY:Integer.parseInt(countStr);
		long repeatInterval = Long.parseLong(params.get("repeatInterval").toString());
		Trigger trigger = new SimpleTrigger(UUIDGenerator.getUUID(), params.get("group").toString(), repeatCount, repeatInterval);
		this.initTrigger(trigger, params);
		this.addTrigger(trigger);
	}
	
	@Override
	public void deleteTriggers(String jobName, String group, String triggerNames) throws BusinessException {
		String[] trigger = triggerNames.split(",");
		for(int i=0;i<trigger.length;i++){
			this.deleteTrigger(trigger[i], group);
		}
	}
	
	@Override
	public String updateStartOrStop(String triggerName, String group) throws BusinessException {
		int flag = -1;
		try {
			flag = scheduler.getTriggerState(triggerName,group);
			switch (flag) {
			case 0 :
				scheduler.pauseTrigger(triggerName, group);
				flag = 1;
				break;
			case 1 :
				scheduler.resumeTrigger(triggerName, group);
				flag = 0;
				break;
			}
		} catch (SchedulerException e) {
			throw new BusinessException("修改定时状态失败", e);
		}
		return "{state:'"+flag+"'}";
	}
}



这种配置就是对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









  


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值