spring 集成Quartz动态定时使用

该博客介绍了如何利用Quartz库替代Spring的@Scheduled定时器,以实现从前台动态传递执行时间来触发后台业务代码的功能。文章详细阐述了Quartz的Scheduler、Trigger和JobDetail三个核心组件,并展示了创建Job任务类、调度器类以及在业务代码中调用调度器的步骤。此外,还提到了程序重启后如何在监听器中重新加载任务。

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

spring自带的@Scheduled 定时器只能在后台固定时间进行处理业务. 无法动态实现定时任务

前段时间项目要求需要从前台向后台传递执行时间动态执行业务代码,从网上找资料了解到Quartz  创建job来实现.

Quartz 设计有三个核心类,分别是 Scheduler(调度器)Job(任务)和 Trigger (触发器),它们是我们使用 Quartz 的关键。

2.1 Scheduler接口

Scheduler翻译成调度器,Quartz通过调度器来注册、暂停、删除Trigger和JobDetail。Scheduler还拥有一个SchedulerContext,顾名思义就是上下文,通过SchedulerContext我们可以获取到触发器和任务的一些信息。

2.2 Trigger接口

Trigger可以翻译成触发器,通过cron表达式或是SimpleScheduleBuilder等类,指定任务执行的周期。系统时间走到触发器指定的时间的时候,触发器就会触发任务的执行。

2.3 JobDetail接口

Job接口是真正需要执行的任务。JobDetail接口相当于将Job接口包装了一下,Trigger和Scheduler实际用到的都是JobDetail。

接下来我来回顾一下 实现步骤

  1. 首先将Quartz 的包集成到项目中 
    quartz-2.3.0-SNAPSHOT.jar
    quartz-jobs-2.3.0-SNAPSHOT.jar

     

  2. 创建 job 任务类 继承quartz包中的job类 重写 execute方法写定时任务业务逻辑.
    public class TimingUpdatePrice implements Job {
        //货源合同列表 service层
        private HtLogisticsOrderDetailService htLogisticsOrderDetailService = SpringContextHolder.getBean(HtLogisticsOrderDetailService.class);
        //货源单价修改记录表 service 层
        private HtOrderDetailModificationHistoryService htOrderDetailModificationHistoryService = SpringContextHolder.getBean(HtOrderDetailModificationHistoryService.class);
        private HtTransportDetailService htTransportDetailService = SpringContextHolder.getBean(HtTransportDetailService.class);
    
    
        /**
         * 写定时任务业务逻辑
         * @param jobExecutionContext
         * @throws JobExecutionException
         */
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
     //获取当前对象
            String historyId = jobExecutionContext.getTrigger().getJobKey().toString().replace(QuartzManage.TRIGGER_GROUP_NAME + ".", "");
            HtOrderDetailModificationHistory htOrderDetailModificationHistory = htOrderDetailModificationHistoryService.get(historyId);
            try{
                HtLogisticsOrderDetail htLogisticsOrderDetail = new HtLogisticsOrderDetail();
                if(htOrderDetailModificationHistory !=null){
                    htLogisticsOrderDetail = htLogisticsOrderDetailService.get(htOrderDetailModificationHistory.getOrderDetailId());
                    if("1".equals(htOrderDetailModificationHistory.getPriceType())){//开票运费单价
                        htLogisticsOrderDetail.setFreight(htOrderDetailModificationHistory.getFreight());
                        htLogisticsOrderDetail.setPriceType("1");
                        htLogisticsOrderDetail.setActualPrice(null);
                    }else {//实际运费单价
                        htLogisticsOrderDetail.setActualPrice(htOrderDetailModificationHistory.getActualPrice());//实际运费单价
                        htLogisticsOrderDetail.setPriceType("2");
                        htLogisticsOrderDetail.setFreight(null);
                    }
                    htLogisticsOrderDetail.setId(htOrderDetailModificationHistory.getOrderDetailId());
                }
                htTransportDetailService.save(htLogisticsOrderDetail,htOrderDetailModificationHistory);
    //            htLogisticsOrderDetailService.save(htLogisticsOrderDetail,htOrderDetailModificationHistory);
    //            htOrderDetailModificationHistory.setIsDone("1");
    //            htOrderDetailModificationHistoryService.save(htOrderDetailModificationHistory);
                QuartzManage.removeJob(historyId);
            }catch (Exception e) {
                e.printStackTrace();
            }
    }

     

  3. 写调度器类  
    public class QuartzManage {
    	
    	
    	private static SchedulerFactory sf = new StdSchedulerFactory();
    	public static final String TRIGGER_GROUP_NAME = "trigger1";
    
    	/**
    	 * 添加一个任务
    	 * 
    	 * @param jobName--任务名称
    	 * @param job--任务执行对象
    	 * @param time--任务触发时机
    	 * @throws Exception
    	 */
    	public static void addJob(Job job, String time, String jobName) throws Exception {
    		boolean isValidate = CronExpression.isValidExpression(time);
    		if (!isValidate)
    			return;
    		Scheduler sched = sf.getScheduler();
    		JobKey jobKey = new JobKey(jobName, TRIGGER_GROUP_NAME);
    		JobDetail jobDetail = JobBuilder.newJob(job.getClass()).withIdentity(jobKey).build();
    		Trigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, jobName)
    				// 每隔一秒执行 并一直重复
    				.withSchedule(CronScheduleBuilder.cronSchedule(time)).build();
    		sched.scheduleJob(jobDetail, trigger);
    		// 启动
    		if (!sched.isShutdown()) {
    			sched.start();
    		}
    	}
    
    	/**
    	 * 修改定时任务
    	 * 
    	 * @param jobName
    	 * @param time
    	 * @throws Exception
    	 */
    	public static void modifyJobTime(Job job, String time, String jobName) throws Exception {
    		boolean isValidate = CronExpression.isValidExpression(time);
    		if (!isValidate)
    			return;
    		removeJob(jobName);
    		addJob(job, time, jobName);
    	}
    
    	/**
    	 * 移除任务
    	 * 
    	 * @param jobName
    	 * @throws Exception
    	 */
    	public static void removeJob(String jobName) throws Exception {
    		Scheduler sched = sf.getScheduler();
    		JobKey jobKey = new JobKey(jobName, TRIGGER_GROUP_NAME);
    		sched.pauseJob(jobKey);// 停止触发器
    		//sched.shutdown(false);// 移除触发器
    		sched.deleteJob(jobKey);// 删除任务
    	}
    }

     

  4. 在业务代码中调用  调度器

public Map<String,Object> save(HttpServletRequest request,HtOrderDetailModificationHistory htOrderDetailModificationHistory) {
		Map<String,Object> result = Maps.newHashMap();
		try {
			String  message = validateModel(htOrderDetailModificationHistory);
			if (StringUtils.isNotBlank(message)){
				result.put("flag", false);
				result.put("message", message);
				return result;
			}
			//设置通用属性
			setCommonProperties(request,htOrderDetailModificationHistory);
			htOrderDetailModificationHistory.setIsDone("0");//不能放到service层
			htOrderDetailModificationHistoryService.save(htOrderDetailModificationHistory);

			String cron = CronExpressionUtils.cronGen(htOrderDetailModificationHistory.getPeriodicModificationTime());
			QuartzManage.addJob(new TimingUpdatePrice(), cron, htOrderDetailModificationHistory.getId());
			result.put("flag", true);
			result.put("message", "保存货源单价修改记录成功");
		} catch (Exception e) {
			result.put("flag", false);
			result.put("message", e.toString());
		}
		return result;
	}

 

 

5.  若程序重启了  内存中的 job任务就不存在了,  需要放在监听器中重新将这些任务加载进来.

这个监听器类 我加web.xml中配置的

<listener>
    <listener-class>com.xiangyou.modules.sys.listener.WebContextListener</listener-class>
  </listener>
public class WebContextListener extends org.springframework.web.context.ContextLoaderListener {
	
	@Override
	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		if (!SystemService.printKeyLoadMessage()){
			return null;
		}
		WebApplicationContext context = super.initWebApplicationContext(servletContext);
		//获取所有的有时效的绑定数据
		HtOrderDetailModificationHistoryService htOrderDetailModificationHistoryService = context.getBean(HtOrderDetailModificationHistoryService.class);
		try{
			HtOrderDetailModificationHistory htOrderDetailModificationHistory = new HtOrderDetailModificationHistory();
			htOrderDetailModificationHistory.setIsDone("0");
			//循环列表,判断是否过期,如果过期,则直接执行,否则添加入定时任务
			List<HtOrderDetailModificationHistory> list = htOrderDetailModificationHistoryService.findList(htOrderDetailModificationHistory);
			Date modificationTime = null;
			for (HtOrderDetailModificationHistory htOrderDetailModificationHistory1 : list) {
				modificationTime = htOrderDetailModificationHistory1.getPeriodicModificationTime();
				if(modificationTime.before(new Date())){ //已经过期
					String cron = CronExpressionUtils.cronGen(new Date());
					QuartzManage.addJob(new TimingUpdatePrice(), cron, htOrderDetailModificationHistory1.getId());
				}else{
					String cron = CronExpressionUtils.cronGen(modificationTime);
					QuartzManage.addJob(new TimingUpdatePrice(), cron, htOrderDetailModificationHistory1.getId());
				}
			}
		}catch (Exception e) {
			e.printStackTrace();
		}
		return context;
	}
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值