Spring+Quartz 从数据库中获取定时任务和定时时间,动态实现对定时任务的增删改查

来源:互联网 发布:魅族6手机备份数据 编辑:程序博客网 时间:2024/05/24 08:34

由于公司的新接得项目要实现一批数据的同步,通过外围厂商提供的一系列各个系统的webervices接口定时将数据同步到我们开发的共享平台上,由于厂商系统的数据是不断在变化以及各系统闲忙时的特点,所以定时同步任务的执行必须在时间上能够动态配置。因此,我们需要动态的从数据库中获取配置信息,以改变各个定时间的执行规则,废话不说了,上代码:(我利用的是ssh框架直接写的,框架搭建不再叙述)

1.创建数据表(我用的是mysql)

DROP TABLE IF EXISTS `t_wsdoc`;CREATE TABLE `t_wsdoc` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `triggername` varchar(50) NOT NULL,  `jobdetailname` varchar(50) NOT NULL,  `cronexpression` varchar(50) NOT NULL,  `targetobject` varchar(50) NOT NULL,  `methodname` varchar(50) NOT NULL,  `concurrent` char(10) NOT NULL DEFAULT '0',  `state` char(10) NOT NULL DEFAULT '1',  `isspringbean` char(10) NOT NULL DEFAULT '0',  `readme` varchar(100) DEFAULT NULL,  `reserved1` varchar(50) DEFAULT NULL,  `reserved2` varchar(50) DEFAULT NULL,  `reserved3` varchar(50) DEFAULT NULL,  `reserved4` varchar(50) DEFAULT NULL,  `reserved5` varchar(50) DEFAULT NULL,  `reserved6` varchar(50) DEFAULT NULL,  `reserved7` varchar(50) DEFAULT NULL,  `reserved8` varchar(50) DEFAULT NULL,  `reserved9` varchar(50) DEFAULT NULL,  `reserved10` varchar(50) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT INTO `t_wsdoc` VALUES ('1', 'triggername', 'detailname', '0/5 * * * * ?', 'com.framework.timer.ISCSynAllData', 'run', '\'0\'', '\'1\'', '\'0\'', '说明', null, null, null, null, null, null, null, null, null, null);

2.创建表对应的实体类

package ...自定义;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.SequenceGenerator;import javax.persistence.Table;import com.framework.model.AbstractEntity;@Entity@Table(name = "WSDOC", schema = "")public class Wsdoc extends AbstractEntity{/** *  */private static final long serialVersionUID = 1L;private Long id;// 设置trigger名称private String triggername;  //设置表达式private String cronexpression;// 设置Job名称private String jobdetailname;//任务类名private String targetobject;//类名对应的方法名private String methodname;//设置是否并发启动任务 0是false 非0是trueprivate String concurrent;// 如果计划任务不存则为1 存在则为0private String state;private String readme;//是否是已经存在的springBean 1是  0 否private String isspringbean;/** 预留字段1 */private String reserved1;/** 预留字段2 */private String reserved2;/** 预留字段3 */private String reserved3;/** 预留字段4 */private String reserved4;/** 预留字段5 */private String reserved5;/** 预留字段6 */private String reserved6;/** 预留字段7 */private String reserved7;/** 预留字段8 */private String reserved8;/** 预留字段9 */private String reserved9;/** 预留字段10 */private String reserved10;// Constructors/** default constructor */public Wsdoc() {}/** full constructor */public Wsdoc(String triggername, String cronexpression,String jobdetailname, String targetobject, String methodname,String concurrent, String state, String readme,String isspringbean) {this.triggername = triggername;this.cronexpression = cronexpression;this.jobdetailname = jobdetailname;this.targetobject = targetobject;this.methodname = methodname;this.concurrent = concurrent;this.state = state;this.readme = readme;this.isspringbean=isspringbean;}@Id@Column(name = "ID", unique = true, nullable = false, precision = 10, scale = 0)//@GeneratedValue(strategy = GenerationType.SEQUENCE,generator="WSDOC_ID") //如果为oracle则可以创建一个序列,便于插入数据用//@SequenceGenerator(initialValue=0,name="WSDOC_ID",sequenceName="WSDOC_ID",allocationSize=1)public Long getId() {return id;}public void setId(Long id) {this.id = id;}    @Column(name = "TRIGGERNAME",nullable = false,length=100)public String getTriggername() {return this.triggername;}public void setTriggername(String triggername) {this.triggername = triggername;}@Column(name = "CRONEXPRESSION",nullable = false,length=100)public String getCronexpression() {return this.cronexpression;}public void setCronexpression(String cronexpression) {this.cronexpression = cronexpression;}@Column(name = "JOBDETAILNAME",nullable = false,length=100)public String getJobdetailname() {return this.jobdetailname;}public void setJobdetailname(String jobdetailname) {this.jobdetailname = jobdetailname;}@Column(name = "TARGETOBJECT",nullable = false,length=100)public String getTargetobject() {return this.targetobject;}public void setTargetobject(String targetobject) {this.targetobject = targetobject;}@Column(name = "METHODNAME",nullable = false,length=100)public String getMethodname() {return this.methodname;}public void setMethodname(String methodname) {this.methodname = methodname;}@Column(name = "CONCURRENT",nullable = false,length=100)public String getConcurrent() {return this.concurrent;}public void setConcurrent(String concurrent) {this.concurrent = concurrent;}@Column(name = "STATE",nullable = false,length=100)public String getState() {return this.state;}public void setState(String state) {this.state = state;}@Column(name = "README",nullable = false,length=100)public String getReadme() {return this.readme;}public void setReadme(String readme) {this.readme = readme;}@Column(name = "ISSPRINGBEAN",nullable = false,length=100)public String getIsspringbean() {return isspringbean;}public void setIsspringbean(String isspringbean) {this.isspringbean = isspringbean;}@Column(name = "RESERVED_1",length=100)public String getReserved1() {return reserved1;}public void setReserved1(String reserved1) {this.reserved1 = reserved1;}@Column(name = "RESERVED_2",length=100)public String getReserved2() {return reserved2;}public void setReserved2(String reserved2) {this.reserved2 = reserved2;}@Column(name = "RESERVED_3",length=100)public String getReserved3() {return reserved3;}public void setReserved3(String reserved3) {this.reserved3 = reserved3;}@Column(name = "RESERVED_4",length=100)public String getReserved4() {return reserved4;}public void setReserved4(String reserved4) {this.reserved4 = reserved4;}@Column(name = "RESERVED_5",length=100)public String getReserved5() {return reserved5;}public void setReserved5(String reserved5) {this.reserved5 = reserved5;}@Column(name = "RESERVED_6",length=100)public String getReserved6() {return reserved6;}public void setReserved6(String reserved6) {this.reserved6 = reserved6;}@Column(name = "RESERVED_7",length=100)public String getReserved7() {return reserved7;}public void setReserved7(String reserved7) {this.reserved7 = reserved7;}@Column(name = "RESERVED_8",length=100)public String getReserved8() {return reserved8;}public void setReserved8(String reserved8) {this.reserved8 = reserved8;}@Column(name = "RESERVED_9",length=100)public String getReserved9() {return reserved9;}public void setReserved9(String reserved9) {this.reserved9 = reserved9;}@Column(name = "RESERVED_10",length=100)public String getReserved10() {return reserved10;}public void setReserved10(String reserved10) {this.reserved10 = reserved10;}}
3.核心Java代码 

package com.framework.timer;import java.text.ParseException;import java.util.Date;import java.util.List;import org.apache.log4j.Logger;import org.quartz.JobDetail;import org.quartz.Scheduler;import org.springframework.beans.BeansException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.scheduling.quartz.CronTriggerBean;import org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean;import cn.edu.svtcc.datas.model.Wsdoc;import cn.edu.svtcc.datas.service.WsdocService;public class QuartzManager implements BeanFactoryAware {private Logger log = Logger.getLogger(QuartzManager.class);private Scheduler scheduler;private static BeanFactory beanFactory = null;   @Autowired    private WsdocService wsdocService;@SuppressWarnings("unused")private void reScheduleJob() throws Exception, ParseException {// 通过查询数据库里计划任务来配置计划任务List<Wsdoc> quartzList = wsdocService.getAllTarger(); //从数据库中获取所有的配置信息,根据自己的获取方式来写,此不赘述
                Wsdoc tbcq=new Wsdoc();tbcq.setTriggername("triggername");tbcq.setCronexpression("0/5 * * * * ?");tbcq.setJobdetailname("detailname");tbcq.setTargetobject("com.framework.timer.ISCSynAllData");tbcq.setMethodname("run");tbcq.setConcurrent("1");tbcq.setState("1");tbcq.setReadme("readme");tbcq.setIsspringbean("0");quartzList.add(tbcq);*///this.getConfigQuartz();if (quartzList != null && quartzList.size() > 0) {for (Wsdoc tbcq1 : quartzList) {configQuatrz(tbcq1);}}}public boolean configQuatrz(Wsdoc tbcq) {boolean result = false;try {// 运行时可通过动态注入的scheduler得到triggerCronTriggerBean trigger = (CronTriggerBean) scheduler.getTrigger(tbcq.getTriggername(), Scheduler.DEFAULT_GROUP);// 如果计划任务已存在则调用修改方法if (trigger != null) {change(tbcq, trigger);} else {// 如果计划任务不存在并且数据库里的任务状态为可用时,则创建计划任务if (tbcq.getState().equals("1")) {this.createCronTriggerBean(tbcq);}}result = true;} catch (Exception e) {result = false;e.printStackTrace();}return result;}public void change(Wsdoc tbcq, CronTriggerBean trigger)throws Exception {// 如果任务为可用if (tbcq.getState().equals("1")) {// 判断从DB中取得的任务时间和现在的quartz线程中的任务时间是否相等// 如果相等,则表示用户并没有重新设定数据库中的任务时间,这种情况不需要重新rescheduleJobif (!trigger.getCronExpression().equalsIgnoreCase(tbcq.getCronexpression())) {trigger.setCronExpression(tbcq.getCronexpression());scheduler.rescheduleJob(tbcq.getTriggername(),Scheduler.DEFAULT_GROUP, trigger);log.info(new Date() + ": 更新" + tbcq.getTriggername() + "计划任务");}} else {// 不可用scheduler.pauseTrigger(trigger.getName(), trigger.getGroup());// 停止触发器scheduler.unscheduleJob(trigger.getName(), trigger.getGroup());// 移除触发器scheduler.deleteJob(trigger.getJobName(), trigger.getJobGroup());// 删除任务log.info(new Date() + ": 删除" + tbcq.getTriggername() + "计划任务");}}/** * 创建/添加计划任务 *  * @param tbcq *            计划任务配置对象 * @throws Exception */public void createCronTriggerBean(Wsdoc tbcq) throws Exception {// 新建一个基于Spring的管理Job类MethodInvokingJobDetailFactoryBean mjdfb = new MethodInvokingJobDetailFactoryBean();mjdfb.setName(tbcq.getJobdetailname());// 设置Job名称// 如果定义的任务类为Spring的定义的Bean则调用 getBean方法if (tbcq.getIsspringbean().equals("1")) {mjdfb.setTargetObject(beanFactory.getBean(tbcq.getTargetobject()));// 设置任务类} else {// 否则直接new对象mjdfb.setTargetObject(Class.forName(tbcq.getTargetobject()).newInstance());// 设置任务类}mjdfb.setTargetMethod(tbcq.getMethodname());// 设置任务方法mjdfb.setConcurrent(tbcq.getConcurrent().equals("0") ? false : true); // 设置是否并发启动任务mjdfb.afterPropertiesSet();// 将管理Job类提交到计划管理类// 将Spring的管理Job类转为Quartz管理Job类JobDetail jobDetail = new JobDetail();jobDetail = (JobDetail) mjdfb.getObject();jobDetail.setName(tbcq.getJobdetailname());scheduler.addJob(jobDetail, true); // 将Job添加到管理类// 新一个基于Spring的时间类CronTriggerBean c = new CronTriggerBean();c.setCronExpression(tbcq.getCronexpression());// 设置时间表达式c.setName(tbcq.getTriggername());// 设置名称c.setJobDetail(jobDetail);// 注入Jobc.setJobName(tbcq.getJobdetailname());// 设置Job名称scheduler.scheduleJob(c);// 注入到管理类scheduler.rescheduleJob(tbcq.getTriggername(), Scheduler.DEFAULT_GROUP,c);// 刷新管理类log.info(new Date() + ": 新建" + tbcq.getTriggername() + "计划任务");}public Scheduler getScheduler() {return scheduler;}public void setScheduler(Scheduler scheduler) {this.scheduler = scheduler;}public void setBeanFactory(BeanFactory factory) throws BeansException {this.beanFactory = factory;}public BeanFactory getBeanFactory() {return beanFactory;}   }
4.测试类代码

package com.framework.timer;import java.util.Date;import org.quartz.SchedulerException;public class ISCSynAllData{  public void run() throws SchedulerException{     System.out.println("开始执行"+new Date());       }}
5.Spring.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:task="http://www.springframework.org/schema/task"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/task   http://www.springframework.org/schema/task/spring-task-3.0.xsd"><!-- 引入属性文件 --><context:property-placeholder location="classpath:config.properties" /><!-- 自动扫描dao和service包(自动注入) --><context:component-scan base-package="com,cn" /><!-- 定时任务配置 实现方式1,利用spring自带的定时器    <task:executor id="executor" pool-size="5" />   -->    <!-- 声明一个具有10个线程的池,每一个对象将获取同样的运行机会    <task:scheduler id="scheduler" pool-size="10" />   -->     <!--  定时器开关  开始    <task:annotation-driven executor="executor" scheduler="scheduler" />--><!--  定时器开关  结束--><!--数据同步 --><!--下面这种quartz定时器是为了实现人工对定时间的启用,停用,调用时间,和删除的操作  --><span style="color:#ff0000;"><!--实现方式二,利用 quartz实现定时器功能--><bean id="quartzManagerBean" class="com.framework.timer.QuartzManager"><property name="scheduler" ref="schedulerManager" /></bean><bean id="quartzManagerJobDetail"class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"><property name="targetObject" ref="quartzManagerBean" /><property name="targetMethod" value="reScheduleJob" /><property name="concurrent" value="false" /></bean><!-- 主定时计划 --><bean id="quartzManagerTrigger"class="org.springframework.scheduling.quartz.SimpleTriggerBean"><property name="jobDetail" ref="quartzManagerJobDetail" /><!-- 延时1分钟 执行任务 --><property name="startDelay" value="300000" /><!-- 任务执行周期 5分钟 --><property name="repeatInterval" value="60000" /></bean><!-- 总管理类 如果将lazy-init='false'那么容器启动就会执行调度程序  --><bean id="schedulerManager" lazy-init="false" autowire="no"class="org.springframework.scheduling.quartz.SchedulerFactoryBean"><property name="triggers"><list><ref bean="quartzManagerTrigger" /></list></property></bean></beans></span>
按照我以上配置流程把代码拷贝过去稍加修改即可实现!

demo代码下载地址:http://download.csdn.net/detail/wwkms/9152293

关于cronexpression时间表达式的说明,详见我的博客《Quartz CronTrigger最完整配置说明》

1 5