ssm项目中动态Quartz定时任务的实现(定时任务存在表中,而不是在.xml中)

来源:互联网 发布:网络发展阶段 编辑:程序博客网 时间:2024/05/22 12:16

大家好,小学生又来为初级者分享一下技术了。这节我们来分享quartz动态定时任务的实现,因为楼主公司项目的需要,所以前端时间自己了解了一下动态更改的quartz定时任务功能。我刚开始也是看了需要帖子,发现大多数定时任务还是写在.xml配置里面的,这样写的最大缺点就是如果因为公司需要把定时任务执行的时间、或者是执行类更换,就需要修改.xml代码并重新提交发布版本才行。为此出了一种写到数据库里的动态定时任务技术。如下......

我在上节讲了maven创建ssm框架的多模块项目,此次也是根据上次的代码进行编写分享的,如有需要可以点击查看上篇博客 maven多模块。

1、我们需要在父项目的pom.xml文件中加入jar依赖:

<dependency><span style="white-space:pre">
<span style="white-space:pre"></span><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>1.8.6</version></dependency><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-log4j12</artifactId><version>1.7.2</version></dependency>

2、为了项目开发方便的需要,我们需要创建两个工具实体类:

(1)定时任务工具类QuartzManager(主要是对quartz的新增、更改、关闭等)

package com.xzhang.util;import java.util.Date;import org.quartz.CronTrigger;import org.quartz.JobDetail;import org.quartz.Scheduler;import org.quartz.SchedulerException;import org.quartz.SchedulerFactory;import org.quartz.Trigger;import org.quartz.impl.StdSchedulerFactory;/**  * @Title: QuartzManager.java* @Package com.xzhang.util* @Description: TODO(定时任务管理类)* @author zx  * @date 2016-8-22 下午3:28:57*/ public class QuartzManager {private static SchedulerFactory gSchedulerFactory = new StdSchedulerFactory();      private static String JOB_GROUP_NAME = "EXTJWEB_JOBGROUP_NAME";      private static String TRIGGER_GROUP_NAME = "EXTJWEB_TRIGGERGROUP_NAME";        /**      * @Description: 添加一个定时任务,使用默认的任务组名,触发器名,触发器组名      *       * @param jobName      *            任务名      * @param cls      *            任务      * @param time      *            时间设置,参考quartz说明文档      *       * @Title: QuartzManager.java      * @Copyright: Copyright (c) 2014      *       * @author Comsys-LZP      * @date 2014-6-26 下午03:47:44      * @version V2.0      */      @SuppressWarnings("unchecked")      public static void addJob(String jobName, Class cls, String time) {          try {              Scheduler sched = gSchedulerFactory.getScheduler();              JobDetail jobDetail = new JobDetail(jobName, JOB_GROUP_NAME, cls);// 任务名,任务组,任务执行类              // 触发器              CronTrigger trigger = new CronTrigger(jobName, TRIGGER_GROUP_NAME);// 触发器名,触发器组              trigger.setCronExpression(time);// 触发器时间设定              sched.scheduleJob(jobDetail, trigger);              // 启动              if (!sched.isShutdown()) {                  sched.start();              }          } catch (Exception e) {              throw new RuntimeException(e);          }      }        /**      * @Description: 添加一个定时任务      *       * @param jobName      *            任务名      * @param jobGroupName      *            任务组名      * @param triggerName      *            触发器名      * @param triggerGroupName      *            触发器组名      * @param jobClass      *            任务      * @param time      *            时间设置,参考quartz说明文档      *       * @Title: QuartzManager.java      * @Copyright: Copyright (c) 2014      *       * @author Comsys-LZP      * @date 2014-6-26 下午03:48:15      * @version V2.0      */      @SuppressWarnings("unchecked")      public static void addJob(String jobName, String jobGroupName,              String triggerName, String triggerGroupName, Class jobClass,              String time) {          try {              Scheduler sched = gSchedulerFactory.getScheduler();              JobDetail jobDetail = new JobDetail(jobName, jobGroupName, jobClass);// 任务名,任务组,任务执行类              // 触发器              CronTrigger trigger = new CronTrigger(triggerName, triggerGroupName);// 触发器名,触发器组              trigger.setCronExpression(time);// 触发器时间设定              sched.scheduleJob(jobDetail, trigger);            // 启动              if (!sched.isShutdown()) {                  sched.start();              }         } catch (Exception e) {              throw new RuntimeException(e);          }      }        /**      * @Description: 修改一个任务的触发时间(使用默认的任务组名,触发器名,触发器组名)      *       * @param jobName      * @param time      *       * @Title: QuartzManager.java      * @Copyright: Copyright (c) 2014      *       * @author Comsys-LZP      * @date 2014-6-26 下午03:49:21      * @version V2.0      */      @SuppressWarnings("unchecked")      public static void modifyJobTime(String jobName, String time) {          try {              Scheduler sched = gSchedulerFactory.getScheduler();              CronTrigger trigger = (CronTrigger) sched.getTrigger(jobName,TRIGGER_GROUP_NAME);              if (trigger == null) {                  return;              }              String oldTime = trigger.getCronExpression();              if (!oldTime.equalsIgnoreCase(time)) {                  JobDetail jobDetail = sched.getJobDetail(jobName,JOB_GROUP_NAME);                  Class objJobClass = jobDetail.getJobClass();                  removeJob(jobName);                  addJob(jobName, objJobClass, time);              }          } catch (Exception e) {              throw new RuntimeException(e);          }      }        /**      * @Description: 修改一个任务的触发时间      *       * @param triggerName      * @param triggerGroupName      * @param time      *       * @Title: QuartzManager.java      * @Copyright: Copyright (c) 2014      *       * @author Comsys-LZP      * @date 2014-6-26 下午03:49:37      * @version V2.0      */      public static void modifyJobTime(String triggerName,              String triggerGroupName, String time) {          try {              Scheduler sched = gSchedulerFactory.getScheduler();              CronTrigger trigger = (CronTrigger) sched.getTrigger(triggerName,triggerGroupName);              if (trigger == null) {                  return;              }              String oldTime = trigger.getCronExpression();              if (!oldTime.equalsIgnoreCase(time)) {                  CronTrigger ct = (CronTrigger) trigger;                  // 修改时间                  ct.setCronExpression(time);                  // 重启触发器                  sched.resumeTrigger(triggerName, triggerGroupName);              }          } catch (Exception e) {              throw new RuntimeException(e);          }      }          /**     * 更新任务时间:先移除、再新增     * @param triggerName     * @param triggerGroupName     * @param time     */    public static void modifyJobTimeTrue(String jobName, String jobGroupName,              String triggerName, String triggerGroupName, Class jobClass,              String time){    //先移除    removeJob(jobName, jobGroupName, triggerName, triggerGroupName);    //再新增    addJob(jobName, jobGroupName, triggerName, triggerGroupName, jobClass, time);    }      /**      * @Description: 移除一个任务(使用默认的任务组名,触发器名,触发器组名)      *       * @param jobName      *       * @Title: QuartzManager.java      * @Copyright: Copyright (c) 2014      *       * @author Comsys-LZP      * @date 2014-6-26 下午03:49:51      * @version V2.0      */      public static void removeJob(String jobName) {          try {              Scheduler sched = gSchedulerFactory.getScheduler();              sched.pauseTrigger(jobName, TRIGGER_GROUP_NAME);// 停止触发器              sched.unscheduleJob(jobName, TRIGGER_GROUP_NAME);// 移除触发器              sched.deleteJob(jobName, JOB_GROUP_NAME);// 删除任务          } catch (Exception e) {              throw new RuntimeException(e);          }      }        /**      * @Description: 移除一个任务      *       * @param jobName      * @param jobGroupName      * @param triggerName      * @param triggerGroupName      *       * @Title: QuartzManager.java      * @Copyright: Copyright (c) 2014      *       * @author Comsys-LZP      * @date 2014-6-26 下午03:50:01      * @version V2.0      */      public static void removeJob(String jobName, String jobGroupName,              String triggerName, String triggerGroupName) {          try {              Scheduler sched = gSchedulerFactory.getScheduler();              sched.pauseTrigger(triggerName, triggerGroupName);// 停止触发器              sched.unscheduleJob(triggerName, triggerGroupName);// 移除触发器              sched.deleteJob(jobName, jobGroupName);// 删除任务          } catch (Exception e) {              throw new RuntimeException(e);          }      }        /**      * @Description:启动所有定时任务      *       *       * @Title: QuartzManager.java      * @Copyright: Copyright (c) 2014      *       * @author Comsys-LZP      * @date 2014-6-26 下午03:50:18      * @version V2.0      */      public static void startJobs() {          try {              Scheduler sched = gSchedulerFactory.getScheduler();              sched.start();          } catch (Exception e) {              throw new RuntimeException(e);          }      }        /**      * @Description:关闭所有定时任务      *       *       * @Title: QuartzManager.java      * @Copyright: Copyright (c) 2014      *       * @author Comsys-LZP      * @date 2014-6-26 下午03:50:26      * @version V2.0      */      public static void shutdownJobs() {          try {              Scheduler sched = gSchedulerFactory.getScheduler();              if (!sched.isShutdown()) {                  sched.shutdown();              }          } catch (Exception e) {              throw new RuntimeException(e);          }      }        /**      * 停止一个job任务      * @param jobkey      * @throws SchedulerException      */      public static void pauseJob(String jobName, String groupName,String triggerName) throws SchedulerException  {     Scheduler sched = gSchedulerFactory.getScheduler();    //sched.pauseTrigger(triggerName, groupName);    //sched.pauseJob(jobName, groupName);    sched.interrupt(jobName, groupName);    }        /**      * 恢复相关的job任务      * @param jobkey      * @throws SchedulerException      */      public static void resumeJob(String jobName, String groupName,String triggerName) throws SchedulerException {      Scheduler sched = gSchedulerFactory.getScheduler();    //sched.resumeTrigger(triggerName, groupName);    sched.resumeJob(jobName, groupName);      }}
(2)SpringContextUtil(spring相关的工具类,主要为了获取到项目中定义的service bean)

/** *  */package com.xzhang.web;import java.util.Locale;import javax.servlet.http.HttpServletRequest;import org.springframework.context.ApplicationContext;import org.springframework.context.ApplicationContextAware;import org.springframework.web.servlet.i18n.SessionLocaleResolver;/** * Spring相关工具类 *  * @author Jian * @date 2012-8-15 */public class SpringContextUtil implements ApplicationContextAware {private static ApplicationContext applicationContext;/** * 实现ApplicationContextAware接口的context注入函数, 将其存入静态变量. */public void setApplicationContext(ApplicationContext applicationContext) {SpringContextUtil.applicationContext = applicationContext;}/** * 取得存储在静态变量中的ApplicationContext. */public static ApplicationContext getApplicationContext() {checkApplicationContext();return applicationContext;}/** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */@SuppressWarnings("unchecked")public static <T> T getBean(String name) {checkApplicationContext();return (T) applicationContext.getBean(name);}/** * 从静态变量ApplicationContext中取得Bean, 自动转型为所赋值对象的类型. */@SuppressWarnings("unchecked")public static <T> T getBean(Class<T> clazz) {checkApplicationContext();return (T) applicationContext.getBeansOfType(clazz);}private static void checkApplicationContext() {if (applicationContext == null)throw new IllegalStateException("applicaitonContext未注入,请在spring-mvc.xml中定义SpringContextUtil");}public static String getMessage(String key, HttpServletRequest request) {return applicationContext.getMessage(key, null, getLocal(request));}public static String getMessage(String key, String[] args, HttpServletRequest request) {return applicationContext.getMessage(key, args, getLocal(request));}public static Locale getLocal(HttpServletRequest request) {Locale locale = (Locale) request.getSession().getAttribute(SessionLocaleResolver.LOCALE_SESSION_ATTRIBUTE_NAME);if (locale == null) {locale = request.getLocale();}return locale;}}


3、创建一张定时任务详细表(即用来存储的所有的定时任务信息),楼主这里用的是MySQL

-- 定时任务表CREATE TABLE t_instmt_quartz(id VARCHAR(100) PRIMARY KEY ,job_group VARCHAR(256) COMMENT '任务组',trigger_group VARCHAR(256) COMMENT '触发器组',  job_name VARCHAR(128) COMMENT '任务名', trigger_name VARCHAR(128) COMMENT '触发器名',   class_name VARCHAR(128) COMMENT '执行代码的类名', enable_status VARCHAR(2) DEFAULT '1' COMMENT '是否禁用:0禁用;1启用',trigger_cron VARCHAR(128) COMMENT '触发器类型(时间) */5 * * * * ?',trigger_status VARCHAR(2) COMMENT '任务状态:0关闭;1运行中;2暂停;',crate_time DATETIME COMMENT '创建时间',update_time DATETIME COMMENT '更新时间',desc_ript VARCHAR(1024) COMMENT '描述');

手动输入一条数据如下图



4、然后根据表创建实体类:QuartzManager;创建相关的dao层、service层

5、创建一个总的定时任务启动类:InstantiationTracingBeanPostProcessor,用来在spring加载完成就进行启动检索所有的定时任务并启动。

package com.xzhang.controller;import java.util.HashMap;import java.util.List;import java.util.Map;import javax.annotation.PostConstruct;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.ApplicationListener;import org.springframework.context.event.ContextRefreshedEvent;import com.alibaba.fastjson.JSON;import com.xzhang.model.InstmtQuartz;import com.xzhang.service.IQuartzService;import com.xzhang.util.QuartzManager;/**  * @Title: InstantiationTracingBeanPostProcessor.java* @Package com.xzhang.controller* @Description: TODO(所有定时任务的启动类:当spring启动的时候它就跟着启动)* @author zx  * @date 2016-8-22 下午4:28:24*/ public class InstantiationTracingBeanPostProcessor  {private IQuartzService quartzService;public IQuartzService getQuartzService() {return quartzService;}public void setQuartzService(IQuartzService quartzService) {this.quartzService = quartzService;}/* spring加载完就执行该方法:init-method="autoLoadTask" */public void autoLoadTask() {//获取到所有需要启动的quartz集合System.out.println("【系统启动】所有定时任务开启...");Map<String, Object> conditions = new HashMap<String, Object>();conditions.put("enablestatus", InstmtQuartz.ENABLE_STATUS_YES);conditions.put("triggerstatus", "");List<InstmtQuartz> quartzList = quartzService.getInstmtQuartzList(conditions);if(null == quartzList)return;for(int i=0;i<quartzList.size();i++){System.out.println("定时任务个数:"+quartzList.size());try {QuartzManager.addJob(quartzList.get(i).getJobname(), quartzList.get(i).getJobgroup(), quartzList.get(i).getTriggername(), quartzList.get(i).getTriggergroup(), Class.forName(quartzList.get(i).getClassname()), quartzList.get(i).getTriggercron());} catch (ClassNotFoundException e) {e.printStackTrace();}}}}


6、同时我们需要在spring-mvc.xml文件中添加如下配置:

<!-- 定义SpringContextUtil工具类 --><bean id="springContextUtil" class="com.xzhang.web.SpringContextUtil" />
<!-- 定时任务:要求所有的定时任务在spring启动之后跟着启动 --><bean id="instantiationTracingBeanPostProcessor" init-method="autoLoadTask" class="com.xzhang.controller.InstantiationTracingBeanPostProcessor" ><property name="quartzService" ref="quartzService" /></bean>

如上代码所示:(1)第一个配置是为了定义声明SpringContextUtil,因为利用了这个工具类去获取了项目中注解的service;

(2)第二个配置是为了在spring启动完成后就执行InstantiationTracingBeanPostProcessor类中的方法autoLoadTask,并注入了quartzService


7、编写一个测试的定时任务执行类,如下:

package com.xzhang.controller;import java.text.SimpleDateFormat;import java.util.Date;import java.util.List;import org.apache.log4j.Logger;import org.quartz.InterruptableJob;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.quartz.UnableToInterruptJobException;import com.xzhang.model.User;import com.xzhang.service.IUserService;import com.xzhang.web.SpringContextUtil;/** * 定时任务--打印测试定时任务是否成功 * @author zx * */public class TestQuartzTask implements InterruptableJob {protected Logger log = Logger.getLogger(this.getClass());private boolean _interrupted = false;/*此处引入相关的service*/private IUserService userService = SpringContextUtil.getBean("userService");@Overridepublic void execute(JobExecutionContext arg0) throws JobExecutionException {if(null == userService){System.out.println("userService为null");}SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");System.out.println(sf.format(new Date())+"定时任务TestQuartzTask.class启动!!!");/* * 获取所有的用户列表,并循环打印 * */List<User> users = userService.getAll();if(null != users && users.size()>0){for(User u : users){//判断是否点击了‘立刻停止’if(_interrupted) {                   System.out.println("定时任务ExpectedBillSmsTask.class立刻停止!!!");                 return;             }System.out.println(sf.format(new Date())+":"+u.getName());}}}@Overridepublic void interrupt() throws UnableToInterruptJobException {System.out.println("【关闭】interrupt执行立刻停止:test定时发送...");log.info("【关闭】interrupt执行立刻停止:test定时发送...");_interrupted = true;}}
注:这个执行类实现了InterruptableJob类,之所以实现这个类主要是想利用InterruptableJob类中private boolean _interrupted = false;这个作用是当在定时任务管理界面点击【立即停止】时,会让_interrupted =true,会中止for循环,也就停止了定时任务的执行了。


好了,就到这里吧,如果大家有疑问可以随时联系楼主这个小学生,楼主的代码里也许会有不合理的地方,欢迎大家指出、相互交流。

楼主QQ:752058871










2 1
原创粉丝点击