Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 465|回复: 0

Spring Quartz 持久化解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-5-5 14:45:00 | 显示全部楼层 |阅读模式


    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);  
    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的优势是就算服务器停止,下次重启能够恢复原先的任务并继续执行.

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2025-2-4 00:57 , Processed in 0.061213 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表