Quartz Scheduler与Spring集成(一) 基础配置与常见问题
2013-05-29 22:36
411 查看
测试环境 Spring3.x Quartz-2.1.7
Spring提供了很多工具类与Quartz框架集成,对集成实现了很好的支持。关于Quartz的技术细节这里不解释,这里只是讲集成的方案,并且需要对Quartz框架很了解的情况才能理解一些细节的东西。
首先让门们先认识一下Spring提供给我们的4个工具类。
这个类提供了对org.quartz.Scheduler的创建与配置,并且会管理它的生命周期与Spring同步。
org.springframework.scheduling.quartz.SchedulerFactoryBean
这个类提供创建JobDetail 并提供缺省配置。
org.springframework.scheduling.quartz.JobDetailFactoryBean
这个类提供创建SimpleTrigger 并提供缺省配置。
org.springframework.scheduling.quartz.SimpleTriggerFactoryBean
这个类提供创建CronTrigger 并提供缺省配置。
org.springframework.scheduling.quartz.CronTriggerFactoryBean
利用Spring提供的4个BeanFactory工具类,我们就可以对Quartz进行集成了。
首先需要在Spring的xml当中把任务配置进去
任务实现类
接下来我们配置一个Trigger, 这里我们使用SimpleTrigger那么我们需要使用SimpleTriggerFactoryBean来创建它
配置的细节不解释 都是SimpleTrigger当中的属性,配置任务什么时间触发,时间间隔等。
最后我们配置Scheduler来把任务加进去,所以我们使用SchedulerFactoryBean。
先来看一下quartz.properties由于我们使用Spring提供的数据源,所以JobStore我们不用配置。
在看Spring.xml
上面这样就完成了基础的配置,那么如果我们需要动态的添加一些任务该如何做呢?
其实跟正常使用quartz没有任何区别,只要在需要用Scheduler的地方进行 Autowired就行了,Spring与自动为我们注入进来。
然后我们可以使用Spring的事物@Transactional,这样任务可以与一些其他的业务方法在同一个事物中,是不是很方便。
还有另外一个需要注意的问题就是如果在 quartz.properties 里面配置了 org.quartz.jobStore.useProperties = true 的话 在启动Spring的时候会抛出序列化失败的异常,其原因是这样的。
org.quartz.jobStore.useProperties = true 设置为true的时候 那么在给任务添加数据的时候就只能是字符串,在上面红色标记的地方,不能出现其他类型,但是在使用SimpleTriggerFactoryBean构建Tirgger的时候它却往里面放了引用类型,所以会导致序列化失败,源代码如下:
上面红色的地方看到了吗,他把jobDetail也放了进去,因为设置了useProperties = true 所以jobDataMap
里面只能存放字符串所以会导致序列化失败,解决办法就是我们复写这个方法,把它删掉就行了。
Spring提供了很多工具类与Quartz框架集成,对集成实现了很好的支持。关于Quartz的技术细节这里不解释,这里只是讲集成的方案,并且需要对Quartz框架很了解的情况才能理解一些细节的东西。
首先让门们先认识一下Spring提供给我们的4个工具类。
这个类提供了对org.quartz.Scheduler的创建与配置,并且会管理它的生命周期与Spring同步。
org.springframework.scheduling.quartz.SchedulerFactoryBean
这个类提供创建JobDetail 并提供缺省配置。
org.springframework.scheduling.quartz.JobDetailFactoryBean
这个类提供创建SimpleTrigger 并提供缺省配置。
org.springframework.scheduling.quartz.SimpleTriggerFactoryBean
这个类提供创建CronTrigger 并提供缺省配置。
org.springframework.scheduling.quartz.CronTriggerFactoryBean
利用Spring提供的4个BeanFactory工具类,我们就可以对Quartz进行集成了。
首先需要在Spring的xml当中把任务配置进去
<bean name="exampleJob" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <!-- 这里是你的具体任务 --> <property name="jobClass" value="com.gary.operation.jobdemo.demo1.HelloJob" /> <!-- 这里要设置为true --> <property name="durability" value="true"></property> </bean>
任务实现类
public class HelloJob implements Job { @Autowired private SqlSession sqlSession; private static Logger _log = LoggerFactory.getLogger(HelloJob.class);public void execute(JobExecutionContext context) throws JobExecutionException { System.out.println("HelloJob.execute()------------------------------------"); } }
接下来我们配置一个Trigger, 这里我们使用SimpleTrigger那么我们需要使用SimpleTriggerFactoryBean来创建它
配置的细节不解释 都是SimpleTrigger当中的属性,配置任务什么时间触发,时间间隔等。
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean"> <property name="jobDetail" ref="exampleJob" /> <property name="startDelay" value="1000" /> <property name="repeatInterval" value="3000" /> <property name="repeatCount" value="1000"/> </bean>
最后我们配置Scheduler来把任务加进去,所以我们使用SchedulerFactoryBean。
先来看一下quartz.properties由于我们使用Spring提供的数据源,所以JobStore我们不用配置。
org.quartz.scheduler.instanceName = MyScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.scheduler.skipUpdateCheck = true #============================================================================ # Configure ThreadPool #============================================================================ org.quartz.threadPool.threadCount = 3 org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadPriority: 5 #============================================================================ # Configure JobStore #============================================================================ #org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreCMT #org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore #org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.MSSQLDelegate org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.useProperties = false #org.quartz.jobStore.dataSource = myDS org.quartz.jobStore.misfireThreshold = 6000
在看Spring.xml
<bean name="MyScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="dataSource" ref="c3p0DataSource" /> <!-- 这里就设置Spring的数据源就行了 --> <property name="schedulerName" value="MyScheduler"></property> <property name="overwriteExistingJobs" value="true"></property> <property name="configLocation" value="classpath:quartz.properties" /> <property name="jobFactory" ref="jobFactory"></property> <property name="triggers"> <list> <ref bean="simpleTrigger"/> </list> </property> <property name="jobDetails"> <list> <ref bean="exampleJob"/> </list> </property> </bean>
上面这样就完成了基础的配置,那么如果我们需要动态的添加一些任务该如何做呢?
public class XXService { @Autowired private Scheduler scheduler; @Transactional public void test() throws SchedulerException { JobDetail job = newJob(HelloJob.class).withIdentity("job1", "group1") .usingJobData("key", "jack") .usingJobData("double", 13.5) .build(); Trigger trigger = newTrigger().withIdentity("trigger1", "group1") // .startAt(DateBuilder.futureDate(1, IntervalUnit.MINUTE)) .startNow() .forJob(job) .withSchedule( SimpleScheduleBuilder.simpleSchedule() .withIntervalInSeconds(2).withRepeatCount(2)) .build(); scheduler.scheduleJob(job, trigger); } }
其实跟正常使用quartz没有任何区别,只要在需要用Scheduler的地方进行 Autowired就行了,Spring与自动为我们注入进来。
然后我们可以使用Spring的事物@Transactional,这样任务可以与一些其他的业务方法在同一个事物中,是不是很方便。
还有另外一个需要注意的问题就是如果在 quartz.properties 里面配置了 org.quartz.jobStore.useProperties = true 的话 在启动Spring的时候会抛出序列化失败的异常,其原因是这样的。
org.quartz.jobStore.useProperties = true 设置为true的时候 那么在给任务添加数据的时候就只能是字符串,在上面红色标记的地方,不能出现其他类型,但是在使用SimpleTriggerFactoryBean构建Tirgger的时候它却往里面放了引用类型,所以会导致序列化失败,源代码如下:
public void afterPropertiesSet() throws ParseException { if (this.name == null) { this.name = this.beanName; } if (this.group == null) { this.group = Scheduler.DEFAULT_GROUP; } if (this.jobDetail != null) { this.jobDataMap.put(JobDetailAwareTrigger.JOB_DETAIL_KEY, this.jobDetail); } if (this.startDelay > 0) { this.startTime = new Date(System.currentTimeMillis() + this.startDelay); } else if (this.startTime == null) { this.startTime = new Date(); } /* SimpleTriggerImpl sti = new SimpleTriggerImpl(); sti.setName(this.name); sti.setGroup(this.group); sti.setJobKey(this.jobDetail.getKey()); sti.setJobDataMap(this.jobDataMap); sti.setStartTime(this.startTime); sti.setRepeatInterval(this.repeatInterval); sti.setRepeatCount(this.repeatCount); sti.setPriority(this.priority); sti.setMisfireInstruction(this.misfireInstruction); this.simpleTrigger = sti; */ Class simpleTriggerClass; Method jobKeyMethod; try { simpleTriggerClass = getClass().getClassLoader().loadClass("org.quartz.impl.triggers.SimpleTriggerImpl"); jobKeyMethod = JobDetail.class.getMethod("getKey"); } catch (ClassNotFoundException ex) { simpleTriggerClass = SimpleTrigger.class; jobKeyMethod = null; } catch (NoSuchMethodException ex) { throw new IllegalStateException("Incompatible Quartz version"); } BeanWrapper bw = new BeanWrapperImpl(simpleTriggerClass); MutablePropertyValues pvs = new MutablePropertyValues(); pvs.add("name", this.name); pvs.add("group", this.group); if (jobKeyMethod != null) { pvs.add("jobKey", ReflectionUtils.invokeMethod(jobKeyMethod, this.jobDetail)); } else { pvs.add("jobName", this.jobDetail.getName()); pvs.add("jobGroup", this.jobDetail.getGroup()); } pvs.add("jobDataMap", this.jobDataMap); pvs.add("startTime", this.startTime); pvs.add("repeatInterval", this.repeatInterval); pvs.add("repeatCount", this.repeatCount); pvs.add("priority", this.priority); pvs.add("misfireInstruction", this.misfireInstruction); bw.setPropertyValues(pvs); this.simpleTrigger = (SimpleTrigger) bw.getWrappedInstance(); }
上面红色的地方看到了吗,他把jobDetail也放了进去,因为设置了useProperties = true 所以jobDataMap
里面只能存放字符串所以会导致序列化失败,解决办法就是我们复写这个方法,把它删掉就行了。
public class CustomSimpleTriggerFactoryBean extends SimpleTriggerFactoryBean { @Override public void afterPropertiesSet() throws java.text.ParseException { super.afterPropertiesSet(); getJobDataMap().remove(JobDetailAwareTrigger.JOB_DETAIL_KEY); } }
相关文章推荐
- spring集成mybatis的常见问题
- Struts和Spring集成配置的一点小问题
- Spring 配置的2个常见问题
- Yii基础应用配置及运行常见问题
- Spring学习总结(21)——Spring集成阿里巴巴数据库连接池DruidDataSource配置及其常见问题汇总
- Struts + Spring + Hibernate 集成常见问题
- mybatis-spring集成:配置多数据库源中遇到的问题
- mybatis-spring集成:配置多数据库源中遇到的问题--MapperScannerConfigurer配置
- Struts和Spring集成配置的一点小问题
- 微服务开发架构——Spring Cloud常见问题与总结<四>Spring Cloud 各组件配置属性
- spring配置常见问题
- mybatis-spring集成:配置多数据库源中遇到的问题
- spring 中配置log4j输出日志常见的一个小问题解决方法
- spring 打入jar包 xml配置路径,加载异常等常见问题解决方法
- iOS 9下的shareSDK集成的常见问题及解决方案
- 开发常见错误解决(2)WSE3.0安装问题,VS2005集成
- 最新SpringMVC + spring3.1.1 + hibernate4.1.0 集成及常见问题
- Spring集成quartz集群配置总结
- VS 2013+Pcl 1.7.2 安装配置及常见问题
- Struts2 + Spring 2 集成配置