Quartz是实现了序列化接口的,包括接口,所以可以使用标准方式序列化到数据库。

而Spring2.5.6在集成Quartz时却未能考虑持久化问题。



Spring对JobDetail进行了封装,却未实现序列化接口,所以持久化的时候会产生NotSerializable问题,这也是网上一直在那边叫嚣为什么不能持久化到数据库问题,哥今天看了下Spring源码,发现Spring对Quartz持久化的问题.

1. 不知道Spring未来会不会对持久化的支持,不过我们可以有如下解决方案,比如改写

Spring的代码,实现序列化接口.

2. 不使用Spring的Fatory,自己实现任务的初始化.

既然Spring不支持持久化,那么持久化任务还是自己编写实现吧,否则每次都需要打包发布,麻烦,自己编写的类与Quartz完全兼容.

注意:为什么Spring不支持外配置任务,可能也是考虑到这方面问题所以才不提供这些任务的执行化支持.[配置文件配置与数据库配置重复]

直接使用Quartz是支持序列化功能,比如直接使用页面配置Quartz界面,设置任务执行时间等属性。

通过配置实现的是不应该初始化到数据库,否则直接在数据库中配置了。不过也是可以配置的,通过改写JobDetailBean.代码如下:

  1. package org.frame.auth.service;
  2. import java.util.Map;
  3. import org.quartz.Job;
  4. import org.quartz.JobDetail;
  5. import org.quartz.Scheduler;
  6. import org.springframework.beans.factory.BeanNameAware;
  7. import org.springframework.beans.factory.InitializingBean;
  8. import org.springframework.scheduling.quartz.DelegatingJob;
  9. import org.springframework.scheduling.quartz.SchedulerFactoryBean;
  10. public class PersistentJobDetailBean extends JobDetail
  11. implements BeanNameAware, InitializingBean {
  12. private static final long serialVersionUID = -4389885435844732405L;
  13. private Class actualJobClass;
  14. private String beanName;
  15. /**
  16. * Overridden to support any job class, to allow a custom JobFactory
  17. * to adapt the given job class to the Quartz Job interface.
  18. * @see SchedulerFactoryBean#setJobFactory
  19. */
  20. public void setJobClass(Class jobClass) {
  21. if (jobClass != null && !Job.class.isAssignableFrom(jobClass)) {
  22. super.setJobClass(DelegatingJob.class);
  23. this.actualJobClass = jobClass;
  24. }
  25. else {
  26. super.setJobClass(jobClass);
  27. }
  28. }
  29. /**
  30. * Overridden to support any job class, to allow a custom JobFactory
  31. * to adapt the given job class to the Quartz Job interface.
  32. */
  33. public Class getJobClass() {
  34. return (this.actualJobClass != null ? this.actualJobClass : super.getJobClass());
  35. }
  36. /**
  37. * Register objects in the JobDataMap via a given Map.
  38. * <p>These objects will be available to this Job only,
  39. * in contrast to objects in the SchedulerContext.
  40. * <p>Note: When using persistent Jobs whose JobDetail will be kept in the
  41. * database, do not put Spring-managed beans or an ApplicationContext
  42. * reference into the JobDataMap but rather into the SchedulerContext.
  43. * @param jobDataAsMap Map with String keys and any objects as values
  44. * (for example Spring-managed beans)
  45. * @see SchedulerFactoryBean#setSchedulerContextAsMap
  46. */
  47. public void setJobDataAsMap(Map jobDataAsMap) {
  48. getJobDataMap().putAll(jobDataAsMap);
  49. }
  50. /**
  51. * Set a list of JobListener names for this job, referring to
  52. * non-global JobListeners registered with the Scheduler.
  53. * <p>A JobListener name always refers to the name returned
  54. * by the JobListener implementation.
  55. * @see SchedulerFactoryBean#setJobListeners
  56. * @see org.quartz.JobListener#getName
  57. */
  58. public void setJobListenerNames(String[] names) {
  59. for (int i = 0; i < names.length; i++) {
  60. addJobListener(names[i]);
  61. }
  62. }
  63. public void setBeanName(String beanName) {
  64. this.beanName = beanName;
  65. }
  66. public void afterPropertiesSet() {
  67. if (getName() == null) {
  68. setName(this.beanName);
  69. }
  70. if (getGroup() == null) {
  71. setGroup(Scheduler.DEFAULT_GROUP);
  72. }
  73. }
  74. }

这里把Spring的ApplicationContext去掉了,因为这个属性没有实现序列化接口。其他配置与原告一致:

  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" " http://www.springframework.org/dtd/spring-beans.dtd ">
  3. <beans default-autowire="byName">
  4. <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">
  5. <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
  6. <property name="url" >
  7. <value><![CDATA[jdbc:mysql://localhost:3306/txl?connectTimeout=1000&useUnicode=true&characterEncoding=utf-8]]></value>
  8. </property>
  9. <property name="username" value="root"/>
  10. <property name="password" value=""/>
  11. </bean>
  12. <bean id="jobDetail" class = "org.frame.auth.service.PersistentJobDetailBean">
  13. <property name="jobClass" value="org.frame.auth.service.PersistentJob"></property>
  14. </bean>
  15. <!-- <bean id="trigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean" >-->
  16. <!--         <property name="jobDetail" ref="jobDetail"></property>-->
  17. <!--         <property name="startDelay" value="1000"></property>-->
  18. <!--         <property name="repeatInterval" value="3000"></property>-->
  19. <!--         <property name="jobDataAsMap">-->
  20. <!--             <map>-->
  21. <!--                 <entry key="message" value="this is trigger"></entry>-->
  22. <!--             </map>-->
  23. <!--         </property>-->
  24. <!-- </bean>-->
  25. <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" >
  26. <property name="jobDetail" ref="jobDetail"/>
  27. <property name="cronExpression">
  28. <value>0/10 * * * * ?</value>
  29. </property>
  30. </bean>
  31. <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
  32. <property name="dataSource" ref="dataSource"></property>
  33. <property name="applicationContextSchedulerContextKey"  value="applicationContextKey" />
  34. <property name="configLocation" value="classpath:quartz.properties"/>
  35. </bean>
  36. </beans>

org.frame.auth.service.PersistentJob这个类很简单,如下:

  1. package org.frame.auth.service;
  2. import org.quartz.Job;
  3. import org.quartz.JobExecutionContext;
  4. import org.quartz.JobExecutionException;
  5. public class PersistentJob implements Job  {
  6. @Override
  7. public void execute(JobExecutionContext context) throws JobExecutionException {
  8. System.out.println("spring quartz!");
  9. }
  10. }

有人可能会说,你这种任务调度持久化就没有意义了,是的,一般持久化到数据库的代码如下:

  1. package org.frame.auth.service;
  2. import java.util.Map;
  3. import org.quartz.JobExecutionContext;
  4. import org.quartz.JobExecutionException;
  5. import org.quartz.StatefulJob;
  6. public class PersistentJob implements StatefulJob  {
  7. @Override
  8. public void execute(JobExecutionContext context) throws JobExecutionException {
  9. // TODO Auto-generated method stub
  10. Map map = context.getJobDetail().getJobDataMap();
  11. System.out.println("["+context.getJobDetail().getName()+"]"+map.get("message"));
  12. map.put("message", "updated Message");
  13. }
  14. }

这样的话,信息message就会持久化到数据库中了.可以建立系统的连锁调度,这根据你的业务需求了.

在Spring中配置的任务通过我这种修改是可以运行,不过每次运行都需要把原先的任务删除,否则会提示任务已经存在,Quartz的优势是就算服务器停止,下次重启能够恢复原先的任务并继续执行.

Spring Quartz 持久化解决方案的更多相关文章

  1. 基于spring+quartz的分布式定时任务框架

    问题背景 我公司是一个快速发展的创业公司,目前有200人,主要业务是旅游和酒店相关的,应用迭代更新周期比较快,因此,开发人员花费了更多的时间去更=跟上迭代的步伐,而缺乏了对整个系统的把控 没有集群之前 ...

  2. Spring+Quartz 集群

    这几天给Spring+Quartz的集群折腾得死去活来,google了无数页总算搞定,记下一些要点备以后使用. 单独的Quartz集群在http://unmi.blogjava.net/有Unmi翻译 ...

  3. Spring+quartz 实现定时任务job集群配置

    为什么要有集群定时任务? 因为如果多server都触发相同任务,又同时执行,那在99%的场景都是不适合的.比如银行每晚24:00都要汇总营业额.像下面3台server同时进行汇总,最终计算结果可能是真 ...

  4. Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群

    Spring+quartz集群配置,Spring定时任务集群,quartz定时任务集群 >>>>>>>>>>>>>> ...

  5. Spring+quartz 实现定时任务job集群配置【原】

    为什么要有集群定时任务? 因为如果多server都触发相同任务,又同时执行,那在99%的场景都是不适合的.比如银行每晚24:00都要汇总营业额.像下面3台server同时进行汇总,最终计算结果可能是真 ...

  6. 【示例】Spring Quartz入门

    JAVA 针对定时任务,有 Timer,Scheduler, Quartz 等几种实现方式,其中最常用的应该就是 Quartz 了. 一. Quartz的基本概念 在开始之前,我们必须了解以下的几个基 ...

  7. Spring quartz Job不能依赖注入,Spring整合quartz Job任务不能注入

    Spring quartz Job不能依赖注入,Spring整合quartz Job任务不能注入 Spring4整合quartz2.2.3中Job任务使用@Autowired不能注入 >> ...

  8. Spring+quartz集群解决多服务器部署定时器重复执行的问题

    一.问题描述 Spring自带的Task虽然能很好使用定时任务,只需要做些简单的配置就可以了.不过如果部署在多台服务器上的时候,这样定时任务会在每台服务器都会执行,造成重复执行. 二.解决方案 Spr ...

  9. spring + quartz 分布式自定义注解

    相关技术 本文采用spring + quartz的方案.使用mysql作为任务的持久化,支持分布式. 自定义注解 1.启用定时任务 @Target(ElementType.TYPE) @Retenti ...

随机推荐

  1. HBase(三)HBase架构与工作原理

    一.系统架构 注意:应该是每一个 RegionServer 就只有一个 HLog,而不是一个 Region 有一个 HLog. 从HBase的架构图上可以看出,HBase中的组件包括Client.Zo ...

  2. 【LOJ】#2672. 「NOI2012」魔幻棋盘

    题解 代码7.1KB,人傻代码长 恶心死我了这代码真的把我写恶心了= = 想一想就知道这个东西--维护到中心的差分,然后用二维线段树维护一下矩形的gcd 嗯,我说完了,你写吧. 首先这个二维线段树的单 ...

  3. jps出现process information unavailable的问题

    jps出现process information unavailable(当然我ps -aux了,确定该进程是存在的),网上查找了原因,我的理解是这样: 因为jps的进程信息是存储在/tmp/hspe ...

  4. flex布局防止被挤压 flex-shrink: 0

    lex布局非常好用,但在开发过程中可能会碰到的一些坑 1.内容超出容器大致情况是:在一个设置了display:flex布局的大容器A中并排放置两个子容器,并且子容器设置flex:1,子容器中都有一个元 ...

  5. php中empty和isset函数

    函数使用格式 empty bool empty ( mixed $var ) 判断变量是否为空. isset bool isset ( mixed $var [ , mixed $... ] ) 判断 ...

  6. react-native第一次开发记录

    1.安装指定版本 react-native init demo --verbose --version 0.41.0 2.更新依赖包 npm install -g npm-check-updates ...

  7. WMRouter:美团外卖Android开源路由框架

    WMRouter是一款Android路由框架,基于组件化的设计思路,功能灵活,使用也比较简单. WMRouter最初用于解决美团外卖C端App在业务演进过程中的实际问题,之后逐步推广到了美团其他App ...

  8. 清北冬令营入学测试[ABCDEF]

    http://tyvj.cn/Contest/861 [1.2.2017] 像我这种蒟蒻只做了前6道还有道不会只拿了暴力分 A 描述 这是一道有背景的题目,小A也是一个有故事的人.但可惜的是这里纸张太 ...

  9. [USACO5.5]Hidden Password

    题目大意: 求字符串最小表示. 思路: 本来按照lbn187的课件,知道SAM可以求字符串最小表示. 然而他并没有提供例题,就自己找了一道做. 大体思想就是把字符串复制一遍接在后面,构建SAM,然后每 ...

  10. 让 Git 全局性的忽略 .DS_Store

    让 Git 全局性的忽略 .DS_Store Mac 中每个目录都会有个文件叫.DS_Store, 用于存储当前文件夹的一些 Meta 信息.每次提交代码时,我都要在代码仓库的 .gitignore ...