Spring 和Quartz2 整合实现动态定时任务

问题起始:

最近要做一个定时任务,使用Spring的定时任务配置也可以实现。但是很多时候,我们常常会遇到需要动态的添加或修改任务,而spring中所提供的定时任务组件却只能够通过修改xml中trigger的配置才能控制定时任务的时间以及任务的启用或停止,这在带给我们方便的同时也失去了动态配置任务的灵活性。我搜索了一些网上的解决方法,都没有很好的解决这个问题,而且大多数提到的解决方案都停留在Quartz 1.x系列版本上,所用到的代码和API已经不能适用于新版本的Spring和Quartz。那么让我们来解决它吧、

知识点补充:

1、quartz任务调度快速入门:

任务调度快速入门

该资料使用 的是旧版本的quarzt,里面的实例化 jobdetail  和 Trigger的方式都不适用了。但是,对很多基础的概念解释的相当清晰。推荐只看概念,加深理解任务调度的工作机制。

2、带参数执行 任务调度

在job中,不可能不需要参数,这时候参数的传递就显得尤为重要了。quartz2提供参数传递方法是:

1).jobDetail.getJobDataMap().put("timerconfig", timerConfig);   将 timerConfig 以map集合的形式传递给  任务执行时的上下文。

2). (TimerConfig) context.getJobDetail().getJobDataMap().get("timerconfig");     context是job接口中execute(JobExecutionContext context);将刚刚传递的timerconfig取出

如果timerconfig是对象,则用get();其他的则使用对应的get方法即可。

3、如何实例化JobDetail

在quartz2中,实例化任务的方式变化较大,是使用builder进行实例化。 JobDetail jobDetail = newJob(MyTask.class) .withIdentity(name, Groupname).build();

4、如何实例化Trigger

Trigger trigger = newTrigger()

.withIdentity(name, Groupname)

.startNow()

.withSchedule(

CronScheduleBuilder

.cronSchedule(new CronExpression(

expression))).build();

此版本不再采用1版本的 SimpleTrigger /cronTrigger.而是在使用调度器(schedule)的时候选择是用 SimpleScheduleBuilder还是 CronScheduleBuilder。

例如: CronScheduleBuilder .cronSchedule(new CronExpression( expression))//采用cronScheduleBuilder生产 cronTrigger定时器

SimpleScheduleBuilder .SimpleSchedule()//采用SimpleScheduleBuilder生产 SimpleTrigger定时器

问题解决:

bean.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
               http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
               http://www.springframework.org/schema/context
               http://www.springframework.org/schema/context/spring-context-4.0.xsd
               http://www.springframework.org/schema/tx
               http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
               http://www.springframework.org/schema/aop
               http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
               ">

   <!-- 调度器  -->
    <bean id="schedulerFactoryBean"   class="org.springframework.scheduling.quartz.SchedulerFactoryBean" lazy-init="false">
    </bean>

</beans>

Mytask,java

/*
 * @(#)MyTask.java	V0.0.1 2015-1-28, 下午8:34:14
 *
 */
package com.jpgk.system.timer.config;

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import com.jpgk.mq.model.TimerConfig;

public class MyTask implements Job {
	private String id;
	private String category;
	private String destination;
	private String uri;
	private String clientid;
	private String content;
	private String expression;
	private String method;
	private TimerConfig timerConfig;// 一组timerconfig数据对象

	// 任务执行覆写
	public void execute(JobExecutionContext context)
			throws JobExecutionException {
		TimerConfig timerConfig = (TimerConfig) context.getJobDetail()
				.getJobDataMap().get("timerconfig");
		// 属性赋值
		initPrivate(timerConfig);
		System.out.println(timerConfig.getContent());
	}

	// 初始化私有属性,这个方法的存在是为了解决 线程池在每次反射实例化MyTask的时候使用无参构造函数,但任务需要这些私有属性作为任务执行的参数
	public void initPrivate(TimerConfig timerconfig) {
		timerConfig = timerconfig;
		category = timerConfig.getCategory().toUpperCase();// 取出任务类型
		uri = timerConfig.getUri();// 取出请求路径
		destination = timerConfig.getDestination();// 取出目的地
		clientid = timerConfig.getClientid();// 客户ID
		expression = timerConfig.getExpression();// 表达式
		content = timerConfig.getContent();// 请求参数,例如 a=1&b=2
		method = timerConfig.getMethod().toUpperCase();
	}

}

调度页面:Testabc.java

/*
 * @(#)Testabc.java	V0.0.1 2015-1-28, 下午8:06:03
 *
 * Copyright 2015 www.ifood517.com. All rights reserved.
 * www.ifood517.com PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.jpgk.mq.temp;

import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

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

import org.quartz.CronExpression;
import org.quartz.CronScheduleBuilder;
import org.quartz.JobDetail;
import org.quartz.SchedulerException;
import org.quartz.Trigger;
import org.quartz.impl.StdScheduler;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.jpgk.mq.model.TimerConfig;
import com.jpgk.mq.service.TimerConfigService;
import com.jpgk.system.timer.config.MyTask;

public class Testabc {

	private static StdScheduler stdScheduler;

	public static void main(String[] args) {

		ApplicationContext context = new ClassPathXmlApplicationContext(
				"classpath:applicationContext.xml");
		// 实例化线程池
		stdScheduler = (StdScheduler) context.getBean("schedulerFactoryBean");
		// 取出数据库配置信息
		TimerConfigService timerConfigService = (TimerConfigService) context
				.getBean("timerstaskservice");
		List<TimerConfig> configs = timerConfigService.selectAll();

		for (int i = 0; i < configs.size(); i++) {
			// 进行任务的调度
			/*
			 * String category = configs.get(i).getCategory();// 取出任务类型 String
			 * uri = configs.get(i).getUri();// 取出请求路径 String destination =
			 * configs.get(i).getDestination();// 取出目的地 String clientid =
			 * configs.get(i).getClientid();// 客户ID String expression =
			 * configs.get(i).getExpression();// 表达式 String content =
			 * configs.get(i).getContent();// 请求参数,例如 a=1&b=2 String method =
			 * configs.get(i).getMethod().toUpperCase();//请求方式
			 */switch (configs.get(i).getCategory()) {
			case "HTTP":
				// 必须要请求路径
				if (configs.get(i).getUri() == ""
						|| configs.get(i).getUri() == null) {
					try {
						throw (new Exception("请求地址不能为空"));
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				// 必须要请频率
				if (configs.get(i).getExpression() == ""
						|| configs.get(i).getExpression() == null) {
					try {
						throw (new Exception("执行频率不能为空"));
					} catch (Exception e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				if (configs.get(i).getMethod().toUpperCase().equals("GET")) {
					// 重新构造uri
					configs.get(i).setUri(
							configs.get(i).getUri() + "?"
									+ configs.get(i).getContent());
				} else {
					// post须考虑其他方式
					System.out.println("aaaa");
				}
				// System.out.println("category->"+category+"uri->"+uri+"destination->"+destination+"clientid->"+clientid+"expression->"+expression+"content->"+content+"method->"+method);
				break;
			default:
				break;
			}

			// 构造任务
			JobDetail jobDetail = initJobdetail(configs.get(i).getClientid(),
					configs.get(i).getClientid() + "Group", configs.get(i));
			// 构造定时器
			Trigger trigger = initTriger(2, configs.get(i).getClientid(),
					configs.get(i).getClientid() + "Group", configs.get(i)
							.getExpression());
			// 注册定时器和任务
			try {
				stdScheduler.scheduleJob(jobDetail, trigger);
			} catch (SchedulerException e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * 实例化一个Trigger,根据type返回simple/Cron Trigger
	 */
	private static Trigger initTriger(int type, String name, String Groupname,
			String expression) {
		try {
			if (type == 1) {
				// 1 simpleTrigger
				// Simp
			} else if (type == 2) {
				// conTrigger
				Trigger trigger = newTrigger()
						.withIdentity(name, Groupname)
						.startNow()
						.withSchedule(
								CronScheduleBuilder
										.cronSchedule(new CronExpression(
												expression))).build();
				return trigger;
			}
		} catch (Exception e) {
		}
		return null;
	}

	/**
	 * 实例化一个JobDetail
	 */
	private static JobDetail initJobdetail(String name, String Groupname,
			TimerConfig timerConfig) {
		JobDetail jobDetail = newJob(MyTask.class)
				.withIdentity(name, Groupname).build();
		// 在每次添加任务的时候要添加额外的参数,这里我传一个对象进行任务私有属性的初始化
		jobDetail.getJobDataMap().put("timerconfig", timerConfig);
		return jobDetail;
	}

}

以上代码涉及到数据库的数据,忽略即可。看看如何实例化JobDetail和Trigger的。留意下怎么在JobDetail中传递TimerConfig参数的。

但是只能说以上代码只是个解决思路,但是任务调度真正的知识不限于这么少。例如,在任务执行过程中强制终止,休眠,更改表达式等。

供参考:任务调度暂停等实现

时间: 2024-12-08 18:26:31

Spring 和Quartz2 整合实现动态定时任务的相关文章

spring与quartz整合实现分布式动态创建,删除,改变执行时间定时任务(mysql数据库)

背景:因为在项目中用到了定时任务,当时想到了spring的quartz,写完发现费了很大功夫,光是整合就花了一上午,其中最大的问题就是版本问题,项目中用的是spring3.2.8的版本,查阅发现,3.0以上的版本需要使用quartz2.X以上版本,我就去官网下载了2.1.7的quartz,结果发现jar包与spring冲突,最后使用了quartz1.6.0版本. spring与quartz整合第一步需要导jar包,这个在百度搜下quartz的jar,下载一个 第二步:分布式定时任务,是基于数据库

spring boot 整合 quartz 集群环境 实现 动态定时任务配置【原】

最近做了一个spring boot 整合 quartz  实现 动态定时任务配置,在集群环境下运行的 任务.能够对定时任务,动态的进行增删改查,界面效果图如下: 1. 在项目中引入jar 2. 将需要的表导入数据库 官网上有不同数据库的脚本,找到对应的,导入即可 3. java 代码 将quartz 的相关配置文件,配置为暴露bean,方便后期引用. 有一处关键的地方,就是注入spring 上下文,也可以算是一个坑.如果,不注入spring 上下文,那么新添加的定时任务job,是新new 的一个

轻量级Java EE企业应用实战(第4版):Struts 2+Spring 4+Hibernate整合开发(含CD光盘1张)

轻量级Java EE企业应用实战(第4版):Struts 2+Spring 4+Hibernate整合开发(含CD光盘1张)(国家级奖项获奖作品升级版,四版累计印刷27次发行量超10万册的轻量级Java EE经典著作) 李刚 编著   ISBN 978-7-121-24253-3 2014年10月出版 定价:108.00元 824页 16开 编辑推荐 国内知名IT图书作家李刚老师基于曾荣获中国书刊发行业协会“年度全行业优秀畅销品种”大奖的<轻量级Java EE企业应用实战(第3版)>全新升级:

MyBatis与Spring、SpringMVC整合

本文主要记录MyBaits与Spring.SpringMVC的整合步骤,并且有普通的整合方式到通过利用MyBatis动态代理的方式整合的比较好的方式的一步一步演化的步骤: 1.基本环境搭建 2.整合的思路 3.第一种整合方法 4.第二种整合方法 1.基本环境搭建 Mybatis3.2.7+spring3.2.0+springmvc3.2.0 获取的方式: 1.可以通过Maven依赖进行添加: 2.可以通过在官方网站上下载MyBatis与Spring的整合包: 总结来说,jar包内容包含如下: M

(一)spring cloud架构整合-springcloud简介

Spring Cloud是一系列框架的有序集合.利用Spring Boot的开发模式简化了分布式系统基础设施的开发,都可以用Spring Boot的开发风格做到一键启动和部署.Spring Cloud将目前比较成熟.经得起实际考验的服务框架组合起来,通过Spring Boot风格进行再封装,屏蔽掉了复杂的配置和实现原理,最终整合出一套简单易懂.易部署和易维护的分布式系统架构平台.Spring Cloud的子项目,大致可分成两类:一类是对现有成熟框架Spring Boot的封装和抽象,也是数量最多

SpringBoot中并发定时任务的实现、动态定时任务的实现(看这一篇就够了)

# 一.在JAVA开发领域,目前可以通过以下几种方式进行定时任务 1.单机部署模式 Timer:jdk中自带的一个定时调度类,可以简单的实现按某一频度进行任务执行.提供的功能比较单一,无法实现复杂的调度任务. ScheduledExecutorService:也是jdk自带的一个基于线程池设计的定时任务类.其每个调度任务都会分配到线程池中的一个线程执行,所以其任务是并发执行的,互不影响. Spring Task:Spring提供的一个任务调度工具,支持注解和配置文件形式,支持Cron表达式,使用

Spring Boot:整合Spring Security

综合概述 Spring Security 是 Spring 社区的一个顶级项目,也是 Spring Boot 官方推荐使用的安全框架.除了常规的认证(Authentication)和授权(Authorization)之外,Spring Security还提供了诸如ACLs,LDAP,JAAS,CAS等高级特性以满足复杂场景下的安全需求.另外,就目前而言,Spring Security和Shiro也是当前广大应用使用比较广泛的两个安全框架. Spring Security 应用级别的安全主要包含两

Rabbit MQ和Spring Boot的整合

消息服务 背景:有时需与其它系统集成来完成相关业务功能,原始的做法是程序内部相互调用,除此之外,还可用消息服务中间件来进行业务处理,使用消息服务中间件处理业务能够提升系统的异步通信和扩展解耦的能力,个人有点面向切面的意思. 一.为什么要使用消息服务? 因为它有很多好处,能解决很多问题: 1.异步处理 2.流量消峰 3.提高效率和可靠性 二.RabbitMQ消息中间件的原理和工作模式 RabbitMQ消息中间件的原理: 1.消息发布者P向RabbitMQ代理(Broker)指定虚拟主机服务器发送消

spring和hibernate整合时报sessionFactory无法获取默认Bean Validation factory

Hibernate 3.6以上版本在用junit测试时会提示错误: Unable to get the default Bean Validation factory spring和hibernate整合时报sessionFactory无法获取默认Bean Validation factory  ,是因为新版hibernate用到新的jar包造成的,默认会自动找验证包,吴国不需要这一步,可以在spring整合hibernate的配置节点中添加如下标红属性: <bean id="sessio