quartz SpringMvc 动态定时任务(quartz2.2)

本文介绍如何使用Quartz实现动态定时任务,包括任务的添加、修改、删除及启动关闭等功能,并提供Spring MVC环境下配置示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java自带定时任务可以解决部分问题但是当我们要动态执行定时任务时,quartz可以帮助我们有效解决这类型问题

代码亲测可用

springmvc中配置注入调度器scheduler,调用定时任务

<!-- quart -->
<!-- 调度类,如果lazy-init="false"容器启动时候回执行调度程序  -->
<bean id="scheduler" lazy-init="false" autowire="no"  class="org.springframework.scheduling.quartz.SchedulerFactoryBean"></bean>

<!-- 用来设置触发时间的,startJobs方法启动调度容器,然后按照上面的触发器,每个1s执行一次myjob2.dosomething()方法 -->
<bean id="quartzManager" class="cn.com.sinosoft.controller.QuartzManager"  lazy-init="true" init-method="startJobs">
	<!-- 注入对象,管理定时任务,还有在类型要用set get方法,否则会报异常	 -->
	<property name="scheduler" ref="scheduler" ></property>

</bean>

代码逻辑

quartzManager的调用方式,

QuartzManager qm = new QuartzManager();//newquartzManager对象
qm.addJob(votes.getName(), "group"+votes.getName(), "trigger"+votes.getName(), "triggerGroup"+votes.getName(), 
							VoteJob.class,CronDateUtils.getCron(sdf.parse(votes.getEnd_time())),sdf.parse(votes.getOpen_time()), sdf.parse(votes.getEnd_time()),sdf.parse(votes.getOpen_time_join()),sdf.parse(votes.getEnd_time_join()),votes.getId());//直接调用给指定方法就ok
QuartzManager 直接copy即可,根据业务需要修改每个方法的传递参数(笔者该方法使用的是cronSchedule调度器,按照日历的格式,定期执行定时任务)
import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.EverythingMatcher;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import cn.com.sinosoft.lisener.MyJobListener;
import cn.com.sinosoft.service.FxActivityService;

public class QuartzManager {
	Logger logger = LoggerFactory.getLogger(this.getClass());
	private Scheduler scheduler;
	@Autowired
	private FxActivityService fxActivityService;
	
//新增定时任务
 @SuppressWarnings({ "unchecked", "rawtypes" })
public void addJob(String jobName,String jobGroupName,String triggerName,String triggerGroupName,Class jobClass,String cron, Date open_time, Date end_time, Date open_time_join, Date end_time_join, String id) {
	//该方法中除了String jobName,String jobGroupName,String triggerName,String triggerGroupName,Class jobClass,String cron 固定以外其他参数可以删除,可以新增
	//注意  Class jobClass  即为自己下边继承JOB接口的实体类
	try {
		 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//设置任务的开始时间
		Date startDate = open_time;
		
		//设置任务的结束时间
		Date endDate = end_time;
		System.out.println("结束时间:"+endDate);
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		//指定要运行的任务,设置人物名,任务组名
        JobDetail jobDetail= JobBuilder.newJob(jobClass).
	    									withIdentity(jobName, jobGroupName).
							            		usingJobData("open_time",sdf.format(open_time)).//将参数存入jondetail中传递到voteJob中,借助	 JobDataMap map = context.getJobDetail().getJobDataMap();*取出
							            		usingJobData("end_time",sdf.format(end_time)).
							            		usingJobData("open_time_join",sdf.format(open_time_join)).
							            		usingJobData("end_time_join",sdf.format(end_time_join)).
							            		usingJobData("id",id).
							            			build();
       
		//配置触发器
		//1新建一个触发器构造类
		TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
		//2设置触发器名,触发器组名
		triggerBuilder.withIdentity(triggerName, triggerGroupName);
		//也可以在这里携带参数,方法与jobdetail中相同
		//设置任务立即执行
		//triggerBuilder.startNow();
		//设置任务开始时间
		triggerBuilder.startAt(startDate);
		//设置任务结束时间
		triggerBuilder.endAt(endDate);
		//3设置触发器时间规则
		triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
		//4触发器构造类创建trigger对象
		CronTrigger trigger = (CronTrigger) triggerBuilder.build();
		//上边创建好的任务和构造器注入到调度器
		scheduler.scheduleJob(jobDetail, trigger);
		 //全局监听
		scheduler.getListenerManager().addJobListener(new MyJobListener(),EverythingMatcher.allJobs());
        //局部监听
        //scheduler.getListenerManager().addJobListener(new MyJobListener(),KeyMatcher.keyEquals(JobKey.jobKey(jobName, jobGroupName)));
        
		//启动调度器
		if(!scheduler.isShutdown()) {
			scheduler.start();
		}
		//挂起定时任务
		//scheduler.standby();
	} catch (Exception e) {
		e.printStackTrace();
	}
	
}
//修改定时任务cron表达式
public void modifyJobTime (String jobName,String jobGroupName,String triggerName,String triggerGroupName,String cron, Date open_time, Date end_time, Date open_time_join, Date end_time_join) {
	//该方法中除了String jobName,String jobGroupName,String triggerName,String triggerGroupName,String cron固定以外其他参数可以删除
	try {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");	
		//设置任务的开始时间
		Date startDate = open_time;
		//设置任务的结束时间
		Date endDate = end_time;
		
		
		
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		TriggerKey triggerKey = TriggerKey.triggerKey(triggerName,triggerGroupName);
		CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
		logger.info("定时任务组名:"+trigger);
		if(trigger == null) {
			logger.info("trigger为空:"+trigger);
			return;
		}
		String oldTime = trigger.getCronExpression();
		if(!oldTime.equalsIgnoreCase(cron)) {
			TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
			triggerBuilder.withIdentity(triggerName,triggerGroupName).
							usingJobData("open_time",sdf.format(open_time)).
			        		usingJobData("end_time",sdf.format(end_time)).
			        		usingJobData("open_time_join",sdf.format(open_time_join)).
			        		usingJobData("end_time_join",sdf.format(end_time_join));
			//triggerBuilder.startNow();
			triggerBuilder.startAt(open_time);
			triggerBuilder.endAt(end_time);
			triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
			trigger = (CronTrigger) triggerBuilder.build();
			scheduler.rescheduleJob(triggerKey, trigger);
			
		
		}
		
	} catch (Exception e) {
		e.printStackTrace();
	}
	
	
}
//删除定时任务
public void removeJob(String jobName,String jobGroupName,
		String triggerName,String triggerGroupName) {
	
	try {
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		TriggerKey triggerKey = TriggerKey.triggerKey(triggerName,triggerGroupName);
		
		scheduler.pauseTrigger(triggerKey);//停止定时任务
		scheduler.unscheduleJob(triggerKey);//移除定时人体五
		scheduler.deleteJob(JobKey.jobKey(jobName
				, jobGroupName));//删除任务
		
		
		
	} catch (Exception e) {
		throw new 	RuntimeException(e);
	}
	
}
//启动所有定时任务
public void startJob() {
	
	try {
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		scheduler.start();
		
	} catch (Exception e) {
		throw new RuntimeException(e);
	}
	
	
}
//关闭所有定时任务
public void shutdownJobs() {
	
	try {
		Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
		if(!scheduler.isShutdown()) {
			
			
			/**
			 * true等待所有job结束后关闭,false直接关闭不等待所有job结束
			 * scheduler.shutdown(true);
			 * scheduler.shutdown(false);
			 */
			scheduler.shutdown();
		}
		
		
	} catch (Exception e) {
		throw new RuntimeException(e);
	}
	
	
}
//得到所有定时任务
public Scheduler getScheduler() {
	return scheduler;
}

//写入定时任务
public void setScheduler(Scheduler scheduler) {
	 this.scheduler = scheduler;
}
}

Vote工作类,将定时任务需要执行的代码放到这里,交给quartz管理到时间可以自动执行,

import java.text.SimpleDateFormat;
import java.util.Date;

import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.TriggerKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import cn.com.sinosoft.service.FxActivityService;

public class VoteJob implements Job {
private Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
private FxActivityService fxActivityService;

@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
	/**
	 * 新增活动,加入到quartz中管理,定期执行,判断活动时间是否超期限,如果超过期限则修改活动状态
	 */
	logger.info("新增定时任务Vote");
	try {
		// 获取时间范围
		//对应quartzManager中传递过来的数据
		 JobDataMap map = context.getJobDetail().getJobDataMap();*
		String open_time = (String) map.get("open_time");
		String end_time = (String) map.get("end_time");
		String open_time_join = (String) map.get("open_time_join");
		String end_time_join = (String) map.get("end_time_join");
		String id = (String) map.get("id");
		// 将字符串转换为date
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		Date open_times = sdf.parse(open_time);
		Date end_times = sdf.parse(end_time);
		Date open_time_joins = sdf.parse(open_time_join);
		Date end_time_joins = sdf.parse(end_time_join);
		
		Date nowtime = new Date();
		sdf.format(nowtime);
		//比较date大小,如果前端大于后边返回值为1,前边小于后边返回-1,相等返回0
		int compareTo = nowtime.compareTo(end_times);
		//当前时间等于结束时间,修改活动状态为无效
		
		 JobKey jobKey = context.getJobDetail().getKey();
        logger.info("工作任务名称:"+jobKey.getName());
        logger.info("工作组名称:"+jobKey.getGroup());
        logger.info("任务类名称(全路径):"+context.getJobDetail().getJobClass().getName());
        logger.info("任务类名称:"+context.getJobDetail().getJobClass().getSimpleName());
        TriggerKey triggerKey = context.getTrigger().getKey();
        logger.info("触发器任务名称:"+triggerKey.getName());
        logger.info("触发器组名称:"+triggerKey.getGroup());
		if(compareTo == 1) {
			logger.info("到期自动结束定时任务");
			//修改活动状态为无效
			int u =  fxActivityService.updateActivityStates(id);
			if(u==1) {
				logger.info("修改任务状态成功");
			}
		}
		//比较开始和结束时间的大小判断活动是否有效
	} catch (Exception e) {
		logger.info("VoteJob逻辑异常");
		e.printStackTrace();
	}


}

}

注意:一个job可以对应多个trigger 但是一个trigger只能对应一个job

工具类

data和cron格式转换

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* 该类提供Quartz的cron表达式与Date之间的转换
* Created by zhangzh on 2016/8/2.
*/
public class CronDateUtils {
   private static final String CRON_DATE_FORMAT = "ss mm HH dd MM ? yyyy";
   private static Logger logger = LoggerFactory.getLogger(CronDateUtils.class);

   /***
    *
    * @param date 时间
    * @return  cron类型的日期
    */
   public static String getCron(final Date  date){
       SimpleDateFormat sdf = new SimpleDateFormat(CRON_DATE_FORMAT);
       String formatTimeStr = "";
       if (date != null) {
           formatTimeStr = sdf.format(date);
       }
       return formatTimeStr;
   }

   /***
    *
    * @param cron Quartz cron的类型的日期
    * @return  Date日期
    */

   public static Date getDate(final String cron) {


   if(cron == null) {
       return null;
   }

   SimpleDateFormat sdf = new SimpleDateFormat(CRON_DATE_FORMAT);
   Date date = null;
   try {
       date = sdf.parse(cron);
   } catch (ParseException e) {
	   logger.info("cron的类型的日期格式转换异常");
       return null;// 此处缺少异常处理,自己根据需要添加
   }
   return date; }}

进阶

初始化时候通过监听启动quartz

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;

import cn.com.sinosoft.controller.QuartzManager;
import cn.com.sinosoft.po.Vote;
import cn.com.sinosoft.quartz.job.VoteJob;
import cn.com.sinosoft.service.FxActivityService;
import cn.com.sinosoft.service.VoteService;
import cn.com.sinosoft.util.CronDateUtils;
@Component
public class IniterListener implements ApplicationListener<ContextRefreshedEvent>{
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	@Autowired
	private FxActivityService fxActivityService;
	@Autowired
	private VoteService voteService;
	@Override
	public void onApplicationEvent(ContextRefreshedEvent arg0) {
		logger.info("bean容器初始化完成之后执行");
		try {
			//查询数据库中所有的活动,判断活动的有效状态,超期的置为无效,
			//Vote vote = new Vote();
			List<Vote> v = voteService.selectAllVoteForUsers();
			for(Vote votes : v) {
				
			Date date = new Date();
			
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				//当前系统时间
				Date d = sdf.parse(sdf.format(date));
				
			
				//Date open = sdf.parse(votes.getOpen_time());
				Date end = sdf.parse(votes.getEnd_time());
				//当前时间大于等于结束时间
				int i = d.compareTo(end);
				if(i==1||i==0) {
					
					//修改当前活动状态置为无效
					 int j = fxActivityService.updateActivityStates(votes.getId());
					 if(j==1) {
						 
						 logger.info("修改活动状态成功");
						 
					 }else {
						 
						 logger.info("修改活动状态失败,失败的活动名称为:"+votes.getId()+"名称:"+votes.getName());
						 
					 }
				}
				//截止时间大于当前时间,同时活动状态为有效
				if(i==-1&&votes.getStatus().equals("0")) {
					logger.info("添加活动到qz:活动名称为:"+votes.getName());
					//有效活动添加到qz中执行
					QuartzManager qm = new QuartzManager();
					qm.addJob(votes.getName(), "group"+votes.getName(), "trigger"+votes.getName(), "triggerGroup"+votes.getName(), 
							VoteJob.class,CronDateUtils.getCron(sdf.parse(votes.getEnd_time())),sdf.parse(votes.getOpen_time()), sdf.parse(votes.getEnd_time()),sdf.parse(votes.getOpen_time_join()),sdf.parse(votes.getEnd_time_join()),votes.getId());
				}else {
					logger.info("无效活动名称为:"+votes.getName());
				}
				
				
				
			
		}
		//未超期的活动注入到qz中动态加载
		
	} catch (Exception e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
}


}

在springmvc.xml中注入监听

<context:component-scan base-package="cn.com.sinosoft.controller"></context:component-scan>
<!-- 初始化完成之后执行监听   bean中为监听器路径	 -->
<bean class="cn.com.sinosoft.lisener.IniterListener"/>

拓展

### 类似java定时任务,固定时间间隔执行定时任务,使用simpleScheduler调度器来执行
	
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.JobListener;
import org.quartz.Scheduler;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.quartz.TriggerKey;
import org.quartz.impl.StdSchedulerFactory;
import org.quartz.impl.matchers.EverythingMatcher;
import org.quartz.impl.matchers.KeyMatcher;
import org.springframework.beans.factory.annotation.Autowired;

import com.sun.net.ssl.KeyManager;

import cn.com.sinosoft.lisener.MyJobListener;
 
public class QuartzManagerSimple {
 
private static SchedulerFactory schedulerFactory = new StdSchedulerFactory();
/**
 * @Description: 添加一个定时任务
 *
 * @param jobName 任务名
 * @param jobGroupName  任务组名
 * @param triggerName 触发器名
 * @param triggerGroupName 触发器组名
 * @param jobClass  任务
 * @param cron   时间设置,参考quartz说明文档
 */
@SuppressWarnings({ "unchecked", "rawtypes" })
public  void addJob(String jobName, String jobGroupName,
                          String triggerName, String triggerGroupName, Class jobClass, String cron) {
    try {
    	//调度器,从工厂中获取调度实例,默认new stschedulerFactory()
        Scheduler sched = StdSchedulerFactory.getDefaultScheduler();
        //sched.setJobFactory(myJobFactory);

        // 任务名,任务组,任务执行类
        JobDetail jobDetail= JobBuilder.newJob(jobClass).withIdentity(jobName, jobGroupName).usingJobData("message","测试jobdateMap").build();
        //logger.info("名称:"+ jobDetail.getKey().getName());
        //logger.info("组名称:"+ jobDetail.getKey().getGroup());
        //logger.info("任务类:"+ jobDetail.getKey().getClass());
        // 触发器
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
        // 触发器名,触发器组
        triggerBuilder.withIdentity(triggerName, triggerGroupName).usingJobData("triggerMessage","trigger中传递的参数");
        triggerBuilder.startNow();//马上启动
        // 触发器时间设定
        //triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
        triggerBuilder.withSchedule(SimpleScheduleBuilder.simpleSchedule().repeatSecondlyForever(5).withRepeatCount(3));//5s重复执行,执行三次
        // 创建Trigger对象
        //CronTrigger trigger = (CronTrigger) triggerBuilder.build();
        Trigger trigger = triggerBuilder.build();

        // 调度容器设置JobDetail和Trigger
        sched.scheduleJob(jobDetail, trigger);
        //每次新建任务之后设置监听属性
        //全局监听
        //sched.getListenerManager().addJobListener(new MyJobListener(),EverythingMatcher.allJobs());
        //局部监听
        //sched.getListenerManager().addJobListener(new MyJobListener(),KeyMatcher.keyEquals(JobKey.jobKey(jobName, jobGroupName)));
        // 启动
        if (!sched.isShutdown()) {
            sched.start();
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

/**
 * @Description: 修改一个任务的触发时间
 *
 * @param jobName
 * @param jobGroupName
 * @param triggerName 触发器名
 * @param triggerGroupName 触发器组名
 * @param cron   时间设置,参考quartz说明文档
 */
public  void modifyJobTime(String jobName,
                                 String jobGroupName, String triggerName, String triggerGroupName, String cron) {
    try {
        Scheduler sched = schedulerFactory.getScheduler();
        //sched.setJobFactory(myJobFactory);
        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);
        CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerKey);
        if (trigger == null) {
            return;
        }

        String oldTime = trigger.getCronExpression();
        if (!oldTime.equalsIgnoreCase(cron)) {
            /** 方式一 :调用 rescheduleJob 开始 */
            // 触发器
            TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
            // 触发器名,触发器组
            triggerBuilder.withIdentity(triggerName, triggerGroupName);
            triggerBuilder.startNow();
            // 触发器时间设定
            triggerBuilder.withSchedule(CronScheduleBuilder.cronSchedule(cron));
            // 创建Trigger对象
            trigger = (CronTrigger) triggerBuilder.build();
            // 方式一 :修改一个任务的触发时间
            sched.rescheduleJob(triggerKey, trigger);
            /** 方式一 :调用 rescheduleJob 结束 */

            /** 方式二:先删除,然后在创建一个新的Job  */
            //JobDetail jobDetail = sched.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
            //Class<? extends Job> jobClass = jobDetail.getJobClass();
            //removeJob(jobName, jobGroupName, triggerName, triggerGroupName);
            //addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, cron);
            /** 方式二 :先删除,然后在创建一个新的Job */
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

/**
 * @Description: 移除一个任务
 *
 * @param jobName
 * @param jobGroupName
 * @param triggerName
 * @param triggerGroupName
 */
public  void removeJob(String jobName, String jobGroupName,
                             String triggerName, String triggerGroupName) {
    try {
        Scheduler sched = schedulerFactory.getScheduler();

        TriggerKey triggerKey = TriggerKey.triggerKey(triggerName, triggerGroupName);

        sched.pauseTrigger(triggerKey);// 停止触发器
        sched.unscheduleJob(triggerKey);// 移除触发器
        sched.deleteJob(JobKey.jobKey(jobName, jobGroupName));// 删除任务
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

/**
 * @Description:启动所有定时任务
 */
public  void startJobs() {
    try {
        Scheduler sched = schedulerFactory.getScheduler();
        sched.start();
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}

/**
 * @Description:关闭所有定时任务
 */
public  void shutdownJobs() {
    try {
        Scheduler sched = schedulerFactory.getScheduler();
        if (!sched.isShutdown()) {
            sched.shutdown();
        }
    } catch (Exception e) {
        throw new RuntimeException(e);
    }
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值