Spring整合Quartz实现动态定时器(三)

quartz的例子已经分享过了,然而。需求总是会在你以为准备好的时候发生变化。

项目要求变更为:不仅仅要使用quartz定时器在配置文件配置,还要支持数据库动态配置,并且不能通过重启生效(在线生效)。

当时就是晴天霹雳,我也就是对spring定时任务入门而已。都不知道能不能实现这个功能。好在天无绝人之路,我在博客上面发现了可以实现该功能的样例。

博客地址:Spring整合Quartz实现动态定时

于是参考这位大神的代码,自己麻溜的配置了一番。效果实现了!跟那博主的是一样的。开心死~~~

以为搞定了。一般连续剧播放到这里,灾难就要开始了。

真的整合到项目的时候发现一个可怕的事情,用定时器跑代码的时候,无法解决bean注入的问题。都是null

于是老夫就用了一个比较low的办法去补这个漏洞,手工获取bean,只有bean为null,我就赋值给哪个bean对象。效果看起来杠杠的,貌似没啥缺点!后面网上找资料发现,这个办法有个弊端,就是会增加服务的开销。

老夫只能含着泪水整改那些代码了。

好在找到另外一位大神的博客:Quartz的使用(解决quartz的job无法注入spring对象)

根据这位博主的做,麻溜的跑了三回,期间因为jar包,环境等等其他问题。终于跑出来该博主的结果!

喜出望外,悲剧又㕛叒叕发生了。动态更改定时任务的方法失败了(有bug)。那可是我整合这个定时器的核心人物呀。

双腿都跪下了,于是自己补全了两个修改的方法。终于实现了我的目的!下面就是我项目中的代码。

会跟上面两位大神的步骤重复,所以只要是重合的部分直接引用他们的。

Spring.XML的配置:

    
      
      
          
      

任务管理类:(修改一个任务的触发时间  方式一 方式二是我补充的)

package com.sap.test.timerTest;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.DateBuilder;
import org.quartz.DateBuilder.IntervalUnit;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.matchers.GroupMatcher;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class QuartzManager {

	@Autowired
	private Scheduler sched;

	/**
	 * @Description 增加一个job
	 * @param jobClass 任务实现类
	 * @param jobName 任务名称
	 * @param jobGroupName 任务组名
	 * @param jobTime 时间表达式 (如:0/5 * * * * ? )
	 */
	public  void addJob(Class jobClass, String jobName,String jobGroupName,String jobTime) {
		try {
			//创建jobDetail实例,绑定Job实现类  
			//指明job的名称,所在组的名称,以及绑定job类
			JobDetail jobDetail = JobBuilder.newJob(jobClass)
					.withIdentity(jobName, jobGroupName)//任务名称和组构成任务key
					.build();
			//定义调度触发规则  
			//使用cornTrigger规则 
			Trigger trigger = TriggerBuilder.newTrigger()
					.withIdentity(jobName, jobGroupName)//触发器key
					.startAt(DateBuilder.futureDate(1, IntervalUnit.SECOND))
					.withSchedule(CronScheduleBuilder.cronSchedule(jobTime))
					.startNow().build();
			//把作业和触发器注册到任务调度中
			sched.scheduleJob(jobDetail, trigger);
			// 启动
			if (!sched.isShutdown()) {
				sched.start();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @Description 增加一个job
	 * @param jobClass  任务实现类
	 * @param jobName  任务名称
	 * @param jobGroupName 任务组名
	 * @param jobTime  时间表达式 (这是每隔多少秒为一次任务)
	 */
	public void addJob(Class jobClass, String jobName,String jobGroupName,int jobTime){
		addJob(jobClass,jobName,jobGroupName,jobTime,-1);
	}

	/**
	 * @Description 增加一个job
	 * @param jobClass 任务实现类
	 * @param jobName  任务名称
	 * @param jobGroupName 任务组名
	 * @param jobTime  时间表达式 (这是每隔多少秒为一次任务)
	 * @param jobTimes  运行的次数 (<0:表示不限次数)
	 */
	public void addJob(Class jobClass, String jobName,String jobGroupName,int jobTime,int jobTimes){
		try {
			JobDetail jobDetail = JobBuilder.newJob(jobClass)
					.withIdentity(jobName, jobGroupName)//任务名称和组构成任务key
					.build();
			//使用simpleTrigger规则
			Trigger trigger=null;
			if(jobTimes<0){
				trigger=TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)  
						.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime))  
						.startNow().build();
			}else{
				trigger=TriggerBuilder.newTrigger().withIdentity(jobName, jobGroupName)  
						.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(1).withIntervalInSeconds(jobTime).withRepeatCount(jobTimes))  
						.startNow().build();
			}
			sched.scheduleJob(jobDetail, trigger);
			if (!sched.isShutdown()) {
				sched.start();
			}
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}

	/**
	 * @Description 修改 一个job的 时间表达式 测试发现这个定时器有问题。
	 * @param jobName
	 * @param jobGroupName
	 * @param jobTime
	 */
    public void updateJob1(String jobName,String jobGroupName,String jobTime){
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);  
            CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);  
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
                    .withSchedule(CronScheduleBuilder.cronSchedule(jobTime))
                    .build();
            //重启触发器
            sched.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }  
    }

    /** 
     * @Description  修改一个任务的触发时间  方式一
     * @param jobName 
     * @param jobGroupName
     * @param jobTime   时间设置,参考quartz说明文档   
     */  
    public void modifyJobTime(String jobName, String jobGroupName, String jobTime) {  
        try {  
        	TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);  
            CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);  
            if (trigger == null) {  
                return;  
            }  

            String oldTime = trigger.getCronExpression();  
            if (!oldTime.equalsIgnoreCase(jobTime)) { 
                // 触发器  
                TriggerBuilder triggerBuilder = TriggerBuilder.newTrigger();
                // 触发器名,触发器组  
                triggerBuilder.withIdentity(jobName, jobGroupName);
                triggerBuilder.startNow();
                // 触发器时间设定  
                triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(jobTime));
                // 创建Trigger对象
                trigger = (CronTrigger) triggerBuilder.build();
                sched.rescheduleJob(triggerKey, trigger);

            }  
        } catch (Exception e) {  
            throw new RuntimeException(e);  
        }  
    }  

	/**
	 * @Description  修改一个任务的触发时间  方式二
	 * @param jobName
	 * @param jobGroupName
	 * @param jobTime   时间设置,参考quartz说明文档   
	 */
	public void updateJob(Class jobClass,String jobName,String jobGroupName,String jobTime){
		deleteJob(jobName,jobGroupName);
		addJob(jobClass,jobName,jobGroupName,jobTime);
	}

	/**
	 * @Description 修改 一个job的  简单的定时任务
	 * @param jobName
	 * @param jobGroupName
	 * @param jobTime
	 */
	public void updateJob(Class jobClass,String jobName,String jobGroupName,int jobTime){
		deleteJob(jobName,jobGroupName) ;
		addJob(jobClass,jobName,jobGroupName,jobTime,-1);
	}

	/**
	 * @Description 删除任务一个job
	 * @param jobName 任务名称
	 * @param jobGroupName 任务组名
	 */
	public  void deleteJob(String jobName,String jobGroupName) {
		try {
			sched.deleteJob(new JobKey(jobName, jobGroupName));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @Description 暂停一个job
	 * @param jobName
	 * @param jobGroupName
	 */
	public void pauseJob(String jobName,String jobGroupName){
		try {
			JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);  
			sched.pauseJob(jobKey);
		} catch (SchedulerException e) {
			e.printStackTrace();
		} 
	}

	/**
	 * @Description 恢复一个job
	 * @param jobName
	 * @param jobGroupName
	 */
	public void resumeJob(String jobName,String jobGroupName){
		try {
			JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
			sched.resumeJob(jobKey);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}

	/**
	 * @Description 立即执行一个job
	 * @param jobName
	 * @param jobGroupName
	 */
	public void runAJobNow(String jobName,String jobGroupName){
		try {
			JobKey jobKey = JobKey.jobKey(jobName, jobGroupName);
			sched.triggerJob(jobKey);
		} catch (SchedulerException e) {
			e.printStackTrace();
		}
	}

	/**
	 * @Description 获取所有计划中的任务列表
	 */
	public List> queryAllJob(){
		List> jobList=null;
		try {
			GroupMatcher matcher = GroupMatcher.anyJobGroup();  
			Set jobKeys = sched.getJobKeys(matcher);
			jobList = new ArrayList>();  
			for (JobKey jobKey : jobKeys) {  
				List triggers = sched.getTriggersOfJob(jobKey);  
				for (Trigger trigger : triggers) {  
					Map map=new HashMap<>();
					map.put("jobName",jobKey.getName());
					map.put("jobGroupName",jobKey.getGroup());
					map.put("description","触发器:" + trigger.getKey());
					Trigger.TriggerState triggerState = sched.getTriggerState(trigger.getKey());  
					map.put("jobStatus",triggerState.name());
					if (trigger instanceof CronTrigger) {  
						CronTrigger cronTrigger = (CronTrigger) trigger;  
						String cronExpression = cronTrigger.getCronExpression();  
						map.put("jobTime",cronExpression);
					}  
					jobList.add(map);  
				}  
			}  
		} catch (SchedulerException e) {
			e.printStackTrace();
		}  
		return jobList;  
	}

	/**
	 * @Description 获取所有正在运行的job
	 */
	public List> queryRunJon(){
		List> jobList=null;
		try {
			List executingJobs = sched.getCurrentlyExecutingJobs();
			jobList = new ArrayList>(executingJobs.size());  
			for (JobExecutionContext executingJob : executingJobs) {  
				Map map=new HashMap();  
				JobDetail jobDetail = executingJob.getJobDetail();  
				JobKey jobKey = jobDetail.getKey();  
				Trigger trigger = executingJob.getTrigger(); 
				map.put("jobName",jobKey.getName());
				map.put("jobGroupName",jobKey.getGroup());
				map.put("description","触发器:" + trigger.getKey());
				Trigger.TriggerState triggerState = sched.getTriggerState(trigger.getKey());  
				map.put("jobStatus",triggerState.name());
				if (trigger instanceof CronTrigger) {  
					CronTrigger cronTrigger = (CronTrigger) trigger;  
					String cronExpression = cronTrigger.getCronExpression();  
					map.put("jobTime",cronExpression);
				}  
				jobList.add(map);  
			}  
		} catch (SchedulerException e) {
			e.printStackTrace();
		}  
		return jobList;  
	}
	
}

 

job类:

package com.yj.quartzjob;
 
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import com.yj.service.WeiXinService;
/**
 * quart test
 *
 */
@Component
public class QuartzJob implements Job{
    @Autowired
    public WeiXinService service;
 
    @Override
    public void execute(JobExecutionContext arg0) throws JobExecutionException {
        SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
        System.out.println("TestQuartJob 的运行 :"+dateFormat.format(new Date()));
        service.getAccessToken();
    }
 
}

测试类:

@RequestMapping("add")
    public void text(){
 
        try {
            String jobName="job1";
            String jobGroupName="job1";
            String jobTime="0/5 * * * * ? ";
            SimpleDateFormat dateFormat=new SimpleDateFormat("yyyy-MM-dd HH-mm-ss");
            System.out.println("TestQuartJob 开始启动:"+dateFormat.format(new Date()));
            quartzManager.addJob(QuartzJob.class,jobName,jobGroupName,jobTime);
        } catch (Exception e) {
            e.printStackTrace();
        } 
    }

监听器:

自定义一个监听类:

貌似Quartz的job在项目重启时,job都失效了,我是把每次启动的job都存放在数据库,然后项目启动时监听器读取数据库的job,然后添加job。

package com.sap.test.timerTest;

import java.util.ArrayList;
import java.util.List;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;

import org.quartz.Job;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.sap.service.api.ISysServerApiSetService;
import com.sap.vo.SysServerApiSetVO;

import utils.TimeExpressionUtil;

/**
 * 容器监听器
 */
@SuppressWarnings("unchecked")
public class QuartzJobListener implements ServletContextListener {
	
	public void contextInitialized(ServletContextEvent arg0) {
		/**初始化定时器任务表的锁状态为0*/
		ISysServerApiSetService sysServerApiSetService = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(ISysServerApiSetService.class);
		SysServerApiSetVO VO = new SysServerApiSetVO();
		VO.setLock_status("0");
		List timeList = new ArrayList<>();
		timeList.add(VO);
		sysServerApiSetService.updateSysServerApiSet(timeList);
		
		/***处理获取数据库的job表,然后遍历循环每个加到job中 ***/
		QuartzManager quartzManager = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(QuartzManager.class);
		
		/**查询数据库获取所有定时任务数据*/	
		List list = sysServerApiSetService.getSysServerApiSetVO();
		
		for (SysServerApiSetVO sysServerApiSetVO : list) {
			try {
				String jobClass = sysServerApiSetVO.getClass_name();
				String jobName = sysServerApiSetVO.getItem_code();
				String jobGroupName = sysServerApiSetVO.getItem_name();
				//判断是接口一还是接口二,判断用表达式定时器还是简单的毫秒定时器。
				if(!TimeExpressionUtil.isNumeric(TimeExpressionUtil.getCron(list,sysServerApiSetVO.getFrequency()))) {
					String jobTime = TimeExpressionUtil.getCron(list,sysServerApiSetVO.getFrequency());
					quartzManager.addJob((Class)(Class.forName(jobClass).newInstance().getClass()), jobName, jobGroupName, jobTime);
				}else {
					int jobTime =  Integer.parseInt(TimeExpressionUtil.getCron(list,sysServerApiSetVO.getFrequency()));
					quartzManager.addJob((Class)(Class.forName(jobClass).newInstance().getClass()), jobName, jobGroupName, jobTime);
				}
				
			} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
				e.printStackTrace();
			}
		}
		System.out.println("QuartzJobListener 启动了");
	}
	
	public void contextDestroyed(ServletContextEvent arg0) {
		/***处理获取数据库的job表,然后遍历循环每个加到job中 ***/
		QuartzManager quartzManager = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(QuartzManager.class);

		/**查询数据库获取所有定时任务数据*/	
		ISysServerApiSetService sysServerApiSetService = WebApplicationContextUtils.getWebApplicationContext(arg0.getServletContext()).getBean(ISysServerApiSetService.class);
		List list = sysServerApiSetService.getSysServerApiSetVO();
		for (SysServerApiSetVO sysServerApiSetVO : list) {
			try {
				String jobName = sysServerApiSetVO.getItem_code();
				String jobGroupName = sysServerApiSetVO.getItem_name();
				quartzManager.deleteJob(jobName, jobGroupName);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		System.out.println("QuartzJobListener 删除了");
	}
	
}

 

这个配置就是项目启动的时候去数据库找到定时器的信息。调度定时任务用!当项目启动执行数据库钟状态为一的所有定时任务。项目关闭的时候关闭所有的定时任务。由于写得比较不友好,怕大家看不懂,建议看第二位大神的博客的最后一个步骤。

PS:不知道为什么不能缺少两个jar包:slf4j-log4j12-1.5.11.jar和slf4j-api-1.5.11.jar

下面的是我数据库的信息:

Spring整合Quartz实现动态定时器(三)_第1张图片

你可能感兴趣的:(定时器)