1. 程式人生 > >quartz與spring整合實現動態任務增刪改查

quartz與spring整合實現動態任務增刪改查

本文最初是為了實現定時推送功能,為推送設定一個時間,到時間後推送到雲巴伺服器。

所以這裡會用到quartz定時任務排程,而且我新增一個定時推送,同時就要新增一個定時任務。所以這裡也涉及到了任務的增刪改查。

以下是程式碼實現:

1、定時任務管理類,實現對任務的CURD

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);  
        }  
    } 
}
2、任務處理類,定時任務所處理的業務
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