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.代码如下:
package org.frame.auth.service;import java.util.Map;import org.quartz.Job;import org.quartz.JobDetail;import org.quartz.Scheduler;import org.springframework.beans.factory.BeanNameAware;import org.springframework.beans.factory.InitializingBean;import org.springframework.scheduling.quartz.DelegatingJob;import org.springframework.scheduling.quartz.SchedulerFactoryBean;public class PersistentJobDetailBean extends JobDetailimplements BeanNameAware, InitializingBean {private static final long serialVersionUID = -4389885435844732405L;private Class actualJobClass;private String beanName;/** * Overridden to support any job class, to allow a custom JobFactory * to adapt the given job class to the Quartz Job interface. * @see SchedulerFactoryBean#setJobFactory */public void setJobClass(Class jobClass) {if (jobClass != null && !Job.class.isAssignableFrom(jobClass)) {super.setJobClass(DelegatingJob.class);this.actualJobClass = jobClass;}else {super.setJobClass(jobClass);}}/** * Overridden to support any job class, to allow a custom JobFactory * to adapt the given job class to the Quartz Job interface. */public Class getJobClass() {return (this.actualJobClass != null ? this.actualJobClass : super.getJobClass());}/** * Register objects in the JobDataMap via a given Map. * <p>These objects will be available to this Job only, * in contrast to objects in the SchedulerContext. * <p>Note: When using persistent Jobs whose JobDetail will be kept in the * database, do not put Spring-managed beans or an ApplicationContext * reference into the JobDataMap but rather into the SchedulerContext. * @param jobDataAsMap Map with String keys and any objects as values * (for example Spring-managed beans) * @see SchedulerFactoryBean#setSchedulerContextAsMap */public void setJobDataAsMap(Map jobDataAsMap) {getJobDataMap().putAll(jobDataAsMap);}/** * Set a list of JobListener names for this job, referring to * non-global JobListeners registered with the Scheduler. * <p>A JobListener name always refers to the name returned * by the JobListener implementation. * @see SchedulerFactoryBean#setJobListeners * @see org.quartz.JobListener#getName */public void setJobListenerNames(String[] names) {for (int i = 0; i < names.length; i++) {addJobListener(names[i]);}}public void setBeanName(String beanName) {this.beanName = beanName;}public void afterPropertiesSet() {if (getName() == null) {setName(this.beanName);}if (getGroup() == null) {setGroup(Scheduler.DEFAULT_GROUP);}}}<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" " http://www.springframework.org/dtd/spring-beans.dtd "><beans default-autowire="byName"> <bean id="dataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" > <value><![CDATA[jdbc:mysql://localhost:3306/txl?connectTimeout=1000&useUnicode=true&characterEncoding=utf-8]]></value> </property> <property name="username" value="root"/> <property name="password" value=""/> </bean><bean id="jobDetail" class = "org.frame.auth.service.PersistentJobDetailBean"><property name="jobClass" value="org.frame.auth.service.PersistentJob"></property></bean><!--<bean id="trigger" >--><!--<property name="jobDetail" ref="jobDetail"></property>--><!--<property name="startDelay" value="1000"></property>--><!--<property name="repeatInterval" value="3000"></property>--><!--<property name="jobDataAsMap">--><!--<map>--><!--<entry key="message" value="this is trigger"></entry>--><!--</map>--><!--</property>--><!--</bean>--><bean id="cronTrigger" > <property name="jobDetail" ref="jobDetail"/> <property name="cronExpression"> <value>0/10 * * * * ?</value> </property></bean><bean id="schedulerFactory" ref="dataSource"></property><property name="applicationContextSchedulerContextKey" value="applicationContextKey" /><property name="configLocation" value="classpath:quartz.properties"/></bean></beans>
package org.frame.auth.service;import org.quartz.Job;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;public class PersistentJob implements Job {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {System.out.println("spring quartz!");}}package org.frame.auth.service;import java.util.Map;import org.quartz.JobExecutionContext;import org.quartz.JobExecutionException;import org.quartz.StatefulJob;public class PersistentJob implements StatefulJob {@Overridepublic void execute(JobExecutionContext context) throws JobExecutionException {// TODO Auto-generated method stubMap map = context.getJobDetail().getJobDataMap();System.out.println("["+context.getJobDetail().getName()+"]"+map.get("message"));map.put("message", "updated Message");}}