quartz與spring整合實現動態任務增刪改查
本文最初是為了實現定時推送功能,為推送設定一個時間,到時間後推送到雲巴伺服器。
所以這裡會用到quartz定時任務排程,而且我新增一個定時推送,同時就要新增一個定時任務。所以這裡也涉及到了任務的增刪改查。
以下是程式碼實現:
1、定時任務管理類,實現對任務的CURD
2、任務處理類,定時任務所處理的業務package com.qbyy.util.yunba.task; import java.util.Date; import org.quartz.JobDetail; import org.quartz.Scheduler; import org.quartz.SimpleTrigger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import org.springframework.stereotype.Component; /** * 定時任務管理類 * * @author FJB * 2015年6月1日 下午3:04:10 */ @SuppressWarnings("rawtypes") @Component("pushQuartzManager") public class PushQuartzManager { @Autowired <span style="white-space:pre"> </span>private SchedulerFactoryBean gSchedulerFactory; private String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME"; //任務組名 private String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME"; //觸發器名 @Autowired public void setgSchedulerFactory(SchedulerFactoryBean gSchedulerFactory) { this.gSchedulerFactory = gSchedulerFactory; } /** * @Description: 新增一個定時任務,使用預設的任務組名,觸發器名,觸發器組名 * @param jobName 任務名 * @param cls 任務 * @param time 時間設定【我這裡用的是java.util.Date,這樣可以直接查詢出資料庫的日期,並設定為定時任務的開始時間】 */ public void addJob(String jobName, Class cls, Date startTime) { try { System.out.println("新增定時任務"+jobName); //Scheduler sched = schedulerFactoryBean.getScheduler(); Scheduler sched = gSchedulerFactory.getScheduler(); JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, cls);// 任務名,任務組,任務執行類 //jobDetail.getJobDataMap().put("targetObjectId", jobName); // 觸發器 SimpleTrigger simpleTrigger = new SimpleTrigger(jobName, TRIGGER_GROUP_NAME); simpleTrigger.setStartTime(startTime); simpleTrigger.setRepeatCount(0);<span style="white-space:pre"> </span>//重複次數為0,不重複 sched.scheduleJob(jobDetail, simpleTrigger); // 啟動 if (!sched.isShutdown()) { sched.start(); } } catch (Exception e) { throw new RuntimeException(e); } } /** * 修改定時任務 * @param jobName 任務名 * @param time 時間 */ public void modifyJobTime(String jobName, Date time) { try { //Scheduler sched = schedulerFactoryBean.getScheduler(); Scheduler sched = gSchedulerFactory.getScheduler(); SimpleTrigger trigger = (SimpleTrigger) sched.getTrigger(jobName,TRIGGER_GROUP_NAME); if (trigger == null) { return; } Date oldTime = trigger.getStartTime(); if (!oldTime.equals(time)) { System.out.println("時間不相等,修改時間"); JobDetail jobDetail = sched.getJobDetail(jobName,JOB_GROUP_NAME); Class objJobClass = jobDetail.getJobClass(); removeJob(jobName); addJob(jobName, objJobClass, time); } } catch (Exception e) { throw new RuntimeException(e); } } /** * 移除一個定時任務 * @param jobName */ public void removeJob(String jobName) { try { Scheduler sched = gSchedulerFactory.getScheduler(); sched.pauseTrigger(jobName, TRIGGER_GROUP_NAME);// 停止觸發器 sched.unscheduleJob(jobName, TRIGGER_GROUP_NAME);// 移除觸發器 sched.deleteJob(jobName, JOB_GROUP_NAME);// 刪除任務 } catch (Exception e) { throw new RuntimeException(e); } } }
package com.qbyy.util.yunba.task; import org.apache.log4j.Logger; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.SchedulerContext; import org.springframework.scheduling.quartz.QuartzJobBean; import com.wunding.service.system.PushSendServiceI; /** * 定時任務執行類 * * @author FJB * 2015年6月1日 上午11:29:31 */ public class PushQuartzJob extends QuartzJobBean { Logger logger = Logger.getLogger(PushQuartzJob.class); //【關鍵】推送的業務類,不能直接通過spring註解注入,必須在xml檔案中配置 private PushSendServiceI pushSendService; @Override protected void executeInternal(JobExecutionContext context) throws JobExecutionException { String id=""; try { //獲取JobExecutionContext中的service物件 SchedulerContext skedCtx = context.getScheduler().getContext(); //獲取SchedulerContext中的service //這裡的service就是通過配置檔案 配置的 pushSendService = (PushSendServiceI)skedCtx.get("pushSendService"); id = context.getJobDetail().getName(); pushSendService.sendPush(id); System.out.println("ID= ["+id+"] 的推送,定時傳送成功"); logger.info("ID= ["+id+"] 的推送,定時傳送成功"); } catch (Exception e) { logger.info("ID= ["+id+"] 的推送,定時傳送失敗"); e.printStackTrace(); } } }
3、配置quartz,這個配置檔案要包含到spring的總配置檔案中
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd"> <!-- quartz的排程工廠 --> <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="schedulerContextAsMap"> <map> <!-- 【關鍵】spring 管理的service需要放到這裡,才能夠注入成功<span style="font-family: Arial, Helvetica, sans-serif;">PushQuartzJob 要使用到的業務類要在這裡注入才能使用</span> --> <description>schedulerContextAsMap</description> <entry key="pushSendService" value-ref="pushSendServiceImpl" /> </map> </property> </bean> </beans>
4、業務邏輯類
@Service
@Transactional
public class PushManageServiceImpl extends BaseService implements PushManageServiceI {
@Autowired
private PushManageMapper pushManageMapper;
@Autowired
private PushQuartzManager pushQuartzManager;
@Override
public void savePush(PushManage pushManage) throws Exception {
String pushId = newId();
pushManage.setId(pushId);
//新增定時任務,這裡直接將推送訊息物件的ID作為jobName,這樣做的好處是,在任務執行時可以直接根據jobName到資料庫中查詢推送資訊
pushQuartzManager.addJob(pushId, PushQuartzJob.class, pushManage.getTaskpushtime());
pushManageMapper.save(pushManage);
}
}
5、每2步中,任務執行所呼叫的方法所在類,任務推送類
package com.wunding.service.system.impl;
import java.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.wunding.domain.system.PushManage;
import com.wunding.persistence.system.PushManageMapper;
import com.wunding.service.system.PushSendServiceI;
import com.wunding.util.yunba.YunBaPushUtil;
/**
* 推送定時傳送管理類
*
* @author FJB
* 2015年6月2日 下午3:10:12
*/
@Service
@Transactional
public class PushSendServiceImpl implements PushSendServiceI {
@Autowired
private PushManageMapper pushManageMapper;
@Autowired
private YunBaPushUtil yunBaPushUtil;
@Override
public void sendPush(String id) throws Exception {
PushManage pushManage = new PushManage();
pushManage.setId(id);
Date nowDate = new Date();
pushManage.setPushtime(nowDate);
pushManage.setIsavailable(1);
pushManageMapper.update(pushManage);
PushManage push = pushManageMapper.get(id);
yunBaPublish(push);
}
/**
* 發推送到伺服器
* @param push
*/
private void yunBaPublish(PushManage push){
//調研發送推送的方法
/**
* ----要推送的內容----
* 1.推送內容[msg]
* 2.內容id [contentId]
* 3.內容型別,資訊、考試等 [contentType]
* 4.推送目標人員或部門 [topic or alias]
* 5.按別名或頻道推送 [pushType]
*/
try {
String pushStr = "{'topic': 'topic1', 'msg': '"+push.getMessages()+"', 'qos': 1}";
JSONObject json = new JSONObject(pushStr);
yunBaPushUtil.getSocket().emit("publish", json);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
要注意的地方:第2步中注入的service類與第4步中的業務邏輯類不能是同一個類,這也是我單獨提取出第5步中的類的原因,因為如果是同一個類,會存在相互注入,也就是迴圈注入,會報類似如下的錯誤:
This means that said other beans do not use the final version
of the bean. This is often the
result of S type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit'
flag turned off,
for example.
6、特別宣告:在編碼過程中參考網上多個地方的程式碼,在這裡我也提供參考的連結地址:
(1)http://blog.csdn.net/whaosy/article/details/6298686 這裡參考了在Job中注入service的方法
(2)http://blog.csdn.net/pengpegv5yaya/article/details/37595889 這裡參考了對定時任務的CURD
(3)http://www.ibm.com/developerworks/cn/java/j-quartz/#ibm-pcon 這裡參考了SimpleTrigger