zoukankan      html  css  js  c++  java
  • Spring Quartz 持久化解决方案


    Quartz是实现了序列化接口的,包括接口,所以可以使用标准方式序列化到数据库。
    而Spring2.5.6在集成Quartz时却未能考虑持久化问题。


    Spring对JobDetail进行了封装,却未实现序列化接口,所以持久化的时候会产生NotSerializable问题,这也是网上一直在那边叫嚣为什么不能持久化到数据库问题,哥今天看了下Spring源码,发现Spring对Quartz持久化的问题.
    1. 不知道Spring未来会不会对持久化的支持,不过我们可以有如下解决方案,比如改写
    Spring的代码,实现序列化接口.
    2. 不使用Spring的Fatory,自己实现任务的初始化.

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

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

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

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

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


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

    Java代码  收藏代码
    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.   
    5.   
    6.    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource" destroy-method="close">  
    7.         <property name="driverClassName" value="com.mysql.jdbc.Driver"/>  
    8.   
    9.         <property name="url" >  
    10.             <value><![CDATA[jdbc:mysql://localhost:3306/txl?connectTimeout=1000&useUnicode=true&characterEncoding=utf-8]]></value>  
    11.         </property>  
    12.         <property name="username" value="root"/>  
    13.         <property name="password" value=""/>  
    14.     </bean>  
    15.   
    16.     <bean id="jobDetail" class = "org.frame.auth.service.PersistentJobDetailBean">  
    17.             <property name="jobClass" value="org.frame.auth.service.PersistentJob"></property>  
    18.     </bean>  
    19.   
    20. <!-- <bean id="trigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean" >-->  
    21. <!--         <property name="jobDetail" ref="jobDetail"></property>-->  
    22. <!--         <property name="startDelay" value="1000"></property>-->  
    23. <!--         <property name="repeatInterval" value="3000"></property>-->  
    24. <!--         <property name="jobDataAsMap">-->  
    25. <!--             <map>-->  
    26. <!--                 <entry key="message" value="this is trigger"></entry>-->  
    27. <!--             </map>-->  
    28. <!--         </property>-->  
    29. <!-- </bean>-->  
    30.   
    31.     <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" >  
    32.          <property name="jobDetail" ref="jobDetail"/>  
    33.          <property name="cronExpression">  
    34.              <value>0/10 * * * * ?</value>  
    35.          </property>  
    36.     </bean>  
    37.   
    38.     <bean id="schedulerFactory" class="org.springframework.scheduling.quartz.SchedulerFactoryBean">  
    39.             <property name="dataSource" ref="dataSource"></property>  
    40.             <property name="applicationContextSchedulerContextKey"  value="applicationContextKey" />  
    41.             <property name="configLocation" value="classpath:quartz.properties"/>  
    42.     </bean>  
    43.   
    44. </beans>  



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

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



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

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


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

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

  • 相关阅读:
    2021,6,10 xjzx 模拟考试
    平衡树(二)——Treap
    AtCoder Beginner Contest 204 A-E简要题解
    POJ 2311 Cutting Game 题解
    Codeforces 990G GCD Counting 题解
    NOI2021 SDPTT D2T1 我已经完全理解了 DFS 序线段树 题解
    第三届山东省青少年创意编程与智能设计大赛总结
    Luogu P6042 「ACOI2020」学园祭 题解
    联合省选2021 游记
    Codeforces 1498E Two Houses 题解 —— 如何用结论吊打标算
  • 原文地址:https://www.cnblogs.com/interdrp/p/3506923.html
Copyright © 2011-2022 走看看