1. 程式人生 > >Quartz 之 scheduler 類的方法 【實現一個 quartz 管理類】

Quartz 之 scheduler 類的方法 【實現一個 quartz 管理類】

pause : 暫停一個觸發器。如果是持久化的 quartz,此觸發器的狀態會被寫到庫中,哪怕是重啟應用後,

也不會觸發,因為狀態是持久化的。

若更新 quartz 配置檔案中的該觸發器的屬性,如 cron 表示式,則記憶體和資料庫中已持久化的資料都不會被更新。

resume : 重置一個觸發器的狀態為執行狀態,下次可排程。對一個不處於 pause 狀態的觸發器呼叫此方法無效果。此方法會改變觸發器的持久化狀態。

remove : 刪除一個觸發器(若是 cron 觸發器,則它關聯的 job 也會被刪除),此處,刪除的含義是,記憶體中刪除,若是持久化 quartz,則庫中的 trigger 和 job 也會被刪除。

重啟應用後,若原來的配置檔案不變更,則被刪除的 trigger 和 job 會被加回來,並且處於可觸發的狀態。

以下是完整的管理類。

package org.summer.spi.quartz;

import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.quartz.CronTrigger;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.summer.exception.spe.SummerException;
import org.summer.spi.spe.JobTriggerManageService;

public class JobTriggerManagerServiceImpl implements JobTriggerManageService {

	private Scheduler scheduler;

	private final Logger logger = LoggerFactory.getLogger(this.getClass());
	public void setScheduler(Scheduler scheduler) {
		this.scheduler = scheduler;
	}
	
	public JobTriggerManagerServiceImpl() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public List> getQrtzTriggers()
	{
		try
		{
			String[] triggerGroupNames = scheduler.getTriggerGroupNames();
			List> triggersInfo = new ArrayList();		
			String[] triggerNames = null;
			Trigger trigger = null;		
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			for(int i=0;i curInfo = new HashMap<>();
					trigger = scheduler.getTrigger(triggerNames[j],triggerGroupNames[i]);
					if(trigger instanceof CronTrigger)
					{
						curInfo.put("cron", ((CronTrigger)trigger).getCronExpression());
					}
					else
					{
						curInfo.put("cron","非 cron 觸發器");
					}
					
					curInfo.put("group", trigger.getGroup());
					curInfo.put("name", trigger.getName());
					curInfo.put("status", scheduler.getTriggerState(trigger.getName(), trigger.getGroup()));
					
					curInfo.put("lastTriggerTime", sdf.format(trigger.getPreviousFireTime()));
					curInfo.put("nextTriggerTime", sdf.format(trigger.getNextFireTime()));
					curInfo.put("startTriggerTime", sdf.format(trigger.getStartTime()));
					curInfo.put("endTriggerTime", null != trigger.getEndTime() ? sdf.format(trigger.getEndTime()) : "");
					
					triggersInfo.add(curInfo);
				}				
			}	
			return triggersInfo;
		}
		catch(Exception e)
		{
			throw new SummerException(e);
		}
	}

	@Override
	public void pauseTrigger(String triggerName, String group) {
		try {
			scheduler.pauseTrigger(triggerName, group);
		} catch (SchedulerException e) {
			throw new SummerException(e);
		}
	}

	@Override
	public void resumeTrigger(String triggerName, String group) {
		try {
			scheduler.resumeTrigger(triggerName, group);
		} catch (SchedulerException e) {
			throw new SummerException(e);
		}
	}

	@Override
	public void removeTrigger(String triggerName, String group){
		try {
			scheduler.unscheduleJob(triggerName, group);
		} catch (SchedulerException e) {
			throw new SummerException(e);
		}
	}

	@Override
	public String triggerRelativeJobsRightNow(String triggerName, String group){
		StringBuilder sb = new StringBuilder();
		try {
			String[] jobGroups = scheduler.getJobGroupNames();
			for(String curJobGroup : jobGroups)
			{
				String[] jobs = scheduler.getJobNames(curJobGroup);
				for(String job : jobs)
				{
					try
					{
						Trigger[] triggers = scheduler.getTriggersOfJob(job, curJobGroup);
						if(null != triggers && 1 == triggers.length && 
								triggers[0].getName().equals(triggerName)
								&& triggers[0].getGroup().equals(group))
						{
							scheduler.triggerJobWithVolatileTrigger(job, curJobGroup);
							sb.append(curJobGroup + "." + job).append(" | ");
						}
					}
					catch(Exception innerEx)
					{
						logger.warn("觸發 job " + curJobGroup + "." + job + " 失敗.",innerEx);
					}
				}
			}
		} catch (SchedulerException e) {
			throw new SummerException(e);
		}
		if(0 != sb.length())
			sb.delete(sb.length() - " | ".length(), sb.length());
		return sb.toString();
		
	}

}

以上管理類只適用於 1.8 及以下版本的 Quartz,對於新版本,Scheduler 不再提供一些方法,不再適用。下面給出適用於新版本的觸發器管理類

package ---.---.---.service.impl;

/**
 *  和老版本 Quartz 的觸發器管理類 JobTriggerManagerServiceImpl.java 的實現不一樣,新版本的 Quartz 減少了一些介面,加入了新介面。
 *  如不再提供 triggerJobWithVolatileTrigger 方法。“立即觸發功能” 可以使用 java 反射做。 
 * 
 */

import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.webank.mbp.ccsm.service.JobTriggerManageService;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class JobTriggerManagerServiceImpl implements JobTriggerManageService,ApplicationContextAware {

    @Autowired
    SchedulerFactoryBean schedulerFactoryBean;
    
    private static ApplicationContext applicationContext; // Spring應用上下文環境

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
          this.applicationContext = applicationContext;
    }
    
	public JobTriggerManagerServiceImpl() {
		// TODO Auto-generated constructor stub
	}

	@Override
	public List> getQrtzTriggers() throws SchedulerException
	{
	    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	    Scheduler scheduler = schedulerFactoryBean.getScheduler();
	    GroupMatcher matcher = GroupMatcher.anyTriggerGroup();
	    Set triggerKeys = scheduler.getTriggerKeys(matcher);
		List triggerGroupNames = scheduler.getTriggerGroupNames();
		List> triggersInfo = new ArrayList();
		for(TriggerKey key : triggerKeys)
		{		    
		    Trigger trigger = scheduler.getTrigger(key);
		    
		    Map curInfo = new HashMap<>();
		    if(trigger instanceof CronTrigger)
            {
                curInfo.put("cron", ((CronTrigger)trigger).getCronExpression());
            }
            else
            {
                curInfo.put("cron","非 cron 觸發器");
            }
            
            curInfo.put("group",key.getGroup());
            curInfo.put("name", key.getName());
            curInfo.put("status", scheduler.getTriggerState(key));
            
            curInfo.put("lastTriggerTime", null != trigger.getPreviousFireTime() ? sdf.format(trigger.getPreviousFireTime()) : "");
            curInfo.put("nextTriggerTime", null != trigger.getNextFireTime() ? sdf.format(trigger.getNextFireTime()) : "");
            curInfo.put("startTriggerTime", null != trigger.getStartTime() ? sdf.format(trigger.getStartTime()) : "");
            curInfo.put("endTriggerTime", null != trigger.getEndTime() ? sdf.format(trigger.getEndTime()) : "");
            
            triggersInfo.add(curInfo);
		}
		return triggersInfo;
	}

	@Override
	public void pauseTrigger(String triggerName, String group) throws SchedulerException{
		 schedulerFactoryBean.getScheduler().pauseTrigger(new TriggerKey(triggerName, group));
	}

	@Override
	public void resumeTrigger(String triggerName, String group) throws SchedulerException{
		schedulerFactoryBean.getScheduler().resumeTrigger(new TriggerKey(triggerName, group));
	}

	@Override
	public void removeTrigger(String triggerName, String group) throws SchedulerException{
	    Set keys = getStrictRelativeJob(triggerName, group);
	    
		schedulerFactoryBean.getScheduler().unscheduleJob(new TriggerKey(triggerName, group));
		List keyList = new ArrayList<>();
		keyList.addAll(keys);
		schedulerFactoryBean.getScheduler().deleteJobs(keyList);
	}
	
	/*
	 * 獲得一個 trigger 強關聯的 job. 即 job 只與這一個 trigger 相關聯
	 */
	private Set getStrictRelativeJob(String triggerName, String group) throws SchedulerException
	{
	    Set rets = new HashSet<>();
	    Scheduler scheduler = schedulerFactoryBean.getScheduler();
	    TriggerKey target = new TriggerKey(triggerName, group);
        Set jobKeys = scheduler.getJobKeys(GroupMatcher.anyJobGroup());//GroupMatcher.jobGroupEquals(group)
        for(JobKey key : jobKeys)
        {
            List triggers = (List) scheduler.getTriggersOfJob(key);
            if(null != triggers && 1 == triggers.size() 
                    && triggers.get(0).getKey().equals(target))
            {
                rets.add(key);
            }
        }
        return rets;
	}
	
	private void triggerRightNow(JobKey jobKey) throws SchedulerException
    {
	    Scheduler scheduler = schedulerFactoryBean.getScheduler();
	    Class jobClass = scheduler.getJobDetail(jobKey).getJobClass();
	    Job jobObj = (Job)applicationContext.getBean(jobClass);
	    
	    try
	    {
	        Method targetMethod = jobClass.getDeclaredMethod("executeInternal", new Class[] {JobExecutionContext.class});
	        targetMethod.setAccessible(true);
	        targetMethod.invoke(jobObj, new Object[]{null});
	        targetMethod.setAccessible(false);
	    } 
	    catch(Exception e)
	    {
	        throw new SchedulerException(e);
	    }
    }
	
	@Autowired
	ObjectMapper json;
	@Override
	public String triggerRelativeJobsRightNow(String triggerName, String group)throws SchedulerException{
		StringBuilder sb = new StringBuilder();

	    Scheduler scheduler = schedulerFactoryBean.getScheduler();
	    Trigger trigger = scheduler.getTrigger(new TriggerKey(triggerName, group));
	    
	    Set jobKeys = getStrictRelativeJob(triggerName, group);
	    for(JobKey key : jobKeys)
	    {
	        triggerRightNow(key);
            sb.append(key.getGroup() + "." + key.getName()).append(" | ");
	    }

		if(0 != sb.length())
			sb.delete(sb.length() - " | ".length(), sb.length());
		return sb.toString();
	}
}