Spring与Quartz集成看起来简单,其实还有很多小的细节解决起来比较耗时,本文作为备忘,摘要代码以供参考。
环境:Spring 3.2,Quartz 2.2.x
数据库:mysql 5.5+
一、普通定时器,非Cluster环境:即没有使用Quartz Cluster,每个Spring实例中的定时器都会同时运行,这在分布式环境中并不会带来太多额外的问题,如果你的定时器中有操作数据库的情况,请注意多个定时器同时运行带来的并发问题。
1、spring-quartz.xml
<bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="jobFactory"> <bean class="org.springframework.scheduling.quartz.SpringBeanJobFactory"/> </property> <property name="autoStartup" value="true"/> <property name="triggers"> <list> <ref bean="testTrigger" /> </list> </property> </bean> <bean id="testTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="cronExpression" value="0/10 * * * * ?" /> <property name="jobDetail" ref="testJobDetail" /> </bean> <bean id="testJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"> <property name="targetObject" ref="testJob"/> <property name="targetMethod" value="execute"/> <property name="concurrent" value="false"/> </bean> <bean id="testJob" class="com.test.support.service.job.TestJob"/>
2、TestJob.java
public class TestJob{ private StudentManager studentManager; public void setStudentManager(StudentManager studentManager) { this.studentManager = studentManager; } public void execute() { System.out.println("test" + studentManager); } }
通过上述方式,我们可以看到TestJob无需实现任何额外的接口,只需要借助“MethodInvokingJobDetailFactoryBean”即可实现Job中依赖注入其他Spring Bean,因为此时testJob已经被声明为Spring bean。除此之外,其他的方式均需要额外的操作,才能将spring bean注入到Job中。
二、Cluster方式:基于JDBC方式,将Quartz job、trigger都序列化到数据库中,这种方式的好处也非常明显,当部署多个spring实例时,集群中任何时候“Scheduler”获取lock,并负责管理所有的job和trigger。Cluster模式下,有很多小细节难以解决,而且与spring的集成并不是非常良好,比如jobData必须实现Serializable接口、Job实例无法透明的注入spring bean等。
首先到Quartz的官网,下载quartz的源代码,并找到相应的数据库sql脚本,并执行,最好为quartz相关的表单独创建一个database。执行SQL脚本的主要作用是生成Cluster所需要的table,这一步quartz并不会在运行时为我们完成。(可能脚本有书写错误,比如mysql的script需要修改一处拼写错误)
1、spring-quartz.xml
<bean id="quartzScheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="dataSource" ref="quartzDataSource" /> <property name="quartzProperties"> <props> <prop key="org.quartz.scheduler.instanceName">quartz-cluster</prop> <prop key="org.quartz.scheduler.instanceId">AUTO</prop> <!-- 线程池配置 --> <prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop> <prop key="org.quartz.threadPool.threadCount">6</prop> <prop key="org.quartz.threadPool.threadPriority">5</prop> <!-- JobStore 配置 --> <prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop> <!-- 集群配置 --> <prop key="org.quartz.jobStore.isClustered">true</prop> <prop key="org.quartz.jobStore.clusterCheckinInterval">20000</prop> <prop key="org.quartz.jobStore.maxMisfiresToHandleAtATime">1</prop> <prop key="org.quartz.jobStore.misfireThreshold">120000</prop> <prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop> </props> </property> <property name="schedulerName" value="clusterScheduler" /> <property name="startupDelay" value="15" /> <property name="applicationContextSchedulerContextKey" value="applicationContext" /> </property> <property name="overwriteExistingJobs" value="true" /> <property name="autoStartup" value="true" /> <property name="triggers"> <list> <ref bean="testTrigger" /> </list> </property> </bean> <bean id="testTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean"> <property name="cronExpression" value="0/4 * * * * ?" /> <property name="jobDetail" ref="testJobDetail" /> </bean> <bean id="testJobDetail" class="org.springframework.scheduling.quartz.JobDetailFactoryBean"> <property name="jobClass" value="com.test.support.service.job.TestJob" /> <property name="durability" value="true" /> </bean> <bean id="quartzDataSource" class="org.apache.commons.dbcp.BasicDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"></property> <property name="url" value="jdbc:mysql://192.168.1.121:3306/quartz?useUnicode=true&characterEncoding=UTF-8&autoReconnect=true"></property> <property name="username" value="root"></property> <property name="password" value="root"></property> <property name="maxActive" value="6"></property> <property name="maxIdle" value="1"></property> <property name="minIdle" value="1"></property> <property name="maxWait" value="60000"></property> <property name="defaultAutoCommit" value="true"></property> </bean>
2、TestJob.java
public class TestJob extends QuartzJobBean{ private StudentManager studentManager; public void executeInternal(JobExecutionContext context) throws JobExecutionException { //因为spring无法注入bean,所以需要手动从ApplicationContext中获取 setting(context); System.out.println("test" + studentManager); } protected void setting(JobExecutionContext context) { try { //key来自spring-quartz.xml中“applicationContextSchedulerContextKey”的值 ApplicationContext applicationContext = (ApplicationContext) context.getScheduler().getContext().get("applicationContext"); studentManager = (StudentManager) applicationContext.getBean("studentManager"); } catch (Exception e) { throw new RuntimeException(e); } } }
目前spring尚没有内置的机制来解决自动注入的问题,所以job中的spring bean需要引入一些外部的机制。上述办法就是其中一个。此外还有一种方式:继承SpringBeanJobFactory。
1)spring-quartz.xml
.... <property name="applicationContextSchedulerContextKey" value="applicationContext" /> <property name="jobFactory"> <bean class="com.test.support.service.AutowireSpringBeanJobFactory" /> </property> ....
<context:annotation-config /> <context:component-scan base-package="com.test.support.service.job" />
2)AutowireSpringBeanJobFactory.java
public class AutowireSpringBeanJobFactory extends SpringBeanJobFactory implements ApplicationContextAware { private transient AutowireCapableBeanFactory beanFactory; public void setApplicationContext(final ApplicationContext context) { beanFactory = context.getAutowireCapableBeanFactory(); } @Override protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception { final Object job = super.createJobInstance(bundle); beanFactory.autowireBean(job); return job; } }
3)TestJob.java
@Service public class TestJob extends QuartzJobBean{ @Autowired private StudentManager studentManager; public void executeInternal(JobExecutionContext context) throws JobExecutionException { System.out.println("test" + studentManager); } }
通过继承SpringBeanJobFactory可以实现springBean的自动注入,前提是必须使用“Autowired”注释,不过开发者一定有办法让注释和setter方式同时支持。本人不太喜欢这种方式,感觉和spring耦合过度了,或许不久的将来,spring会提供内部机制解决这些问题。
还有一个很严重的问题,如果基于cluster,那么trigger的class信息将会被序列化到DB中,此后即使从quartz Scheduler配置文件中移除了某个trigger,那么这个trigger仍然会触发,除非删除trigger相应的job类(或者从db中删除trigger的记录),这个问题实在是难以想象,解决这个问题需要重写spring + Quartz的很多集成类,实在是有些麻烦,希望quartz cluster机制能够更加完善。
上述我们提到的几个问题,或许在将来的spring-quartz项目中能够得以解决。否则开发者需要补充太多东西,才能将此架构完善。
相关推荐
以下将详细介绍如何进行Spring与Quartz的整合。 1. **集成步骤** - 添加依赖:首先,确保在项目中添加了Spring和Quartz的相关库。如果是Maven项目,可以在pom.xml文件中加入对应的依赖。 - 配置Quartz:在Spring...
Spring 提供了与 Quartz 集成的模块,使得在 Spring 应用程序中使用 Quartz 更加便捷,包括 Job 实例的管理、触发器的配置以及对 Quartz Scheduler 的控制。 在这个 "spring+quartz demo" 中,我们可以学习到如何将...
Spring-Quartz的集成则将这些概念与Spring的IoC(Inversion of Control)容器相结合,提供了更好的依赖注入支持。以下是一些关键点: 1. **Bean集成**: Spring可以自动将Job实例作为Spring Bean管理,这样你就可以...
在将 Spring 2 与 Quartz 整合到 Web 应用中时,主要涉及以下几个关键知识点: 1. **Spring 2 的核心概念**:Spring 2 提供了 IoC(Inversion of Control,控制反转)和 AOP(Aspect-Oriented Programming,面向切...
在Spring的配置文件中,我们首先需要定义一个`SchedulerFactoryBean`,它是Spring与Quartz的桥梁。例如: ```xml <bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> ...
1. **Spring与Quartz的整合**:Spring 提供了对Quartz的集成支持,通过`org.springframework.scheduling.quartz`包中的类,如`SchedulerFactoryBean`和`ThreadPoolTaskExecutor`,可以轻松地将Quartz纳入Spring的...
当 Spring 与 Quartz 结合使用时,Spring 可以通过其强大的容器管理和配置能力,将 Quartz 集成到应用程序中。例如,Spring 提供了 `org.springframework.scheduling.quartz` 包,该包包含了一些用于配置 Quartz 的...
在Spring框架中集成Quartz是一款常见的任务调度解决方案,它允许开发者在应用中安排定时任务的执行。Quartz是一个开源的作业调度框架,可以用来在Java应用程序中安排复杂的作业任务。以下将详细介绍如何在Spring中...
在压缩包 "Spring3+Quartz2" 中,可能包含的是一个 Spring 3.x 版本与 Quartz2 结合使用的示例项目,你可以通过解压并运行该项目,学习如何在实际项目中实现类似的功能。记得根据你的具体需求进行适当的修改和配置。
本项目来源与网络,本人对项目...直接通过mvn 倒入项目,在Spring-quartz-demo\src\main\webapp\sql 有sql 建立数据库,表 启动tomcat 直接访问http://localhost:8080/Spring-quartz-demo/task/taskList.htm 就可以使用
Spring 提供了与 Quartz 的无缝集成,允许你通过 Spring 的配置文件来管理 Job 和 Trigger。这包括 Job 的声明、Trigger 的设置以及与 Spring Bean 的关联。通过 Spring,你可以利用其强大的依赖注入(DI)和管理...
SpringQuartz是一个强大的任务调度框架,它在Java应用程序中用于自动化执行特定任务,如定时生成文件、统计数据或执行后台清理工作。Quartz是开源的,具有高度灵活的调度功能,能够根据预定义的时间表触发任务,同时...
Spring 和 Quartz 是两个在 Java 开发中非常重要的框架。Spring 是一个全面的后端开发框架,而 Quartz 是一个强大的任务调度库。将它们结合使用,我们可以实现基于 Spring 的应用程序中的定时任务管理。以下是对 ...
【Spring集成Quartz定时任务与数据库实现集群详解】 在企业级应用中,定时任务的管理是必不可少的一部分,Spring框架提供了与Quartz的集成,使得我们可以方便地创建和管理定时任务。Quartz是一款强大的、开放源代码...
Quartz是一个开源的作业调度框架,而Spring通过提供一个简洁的API使得与Quartz的集成变得简单。以下是对Spring整合Quartz使用实例的详细说明: 1. **Quartz简介** Quartz是一个强大的、完全开源的作业调度框架,它...
在Java开发领域,Spring框架和Quartz库是两个非常重要的组件。Spring是一个全面的企业级应用框架,它提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性,帮助开发者构建高效、灵活的Java应用程序...
在IT行业中,Spring框架是Java企业级应用开发的首选,而Quartz则是一个强大的任务调度库,常用于实现定时任务。本篇文章将深入探讨如何在Spring环境中集成Quartz以构建一个高可用的集群。 首先,我们需要理解Spring...
Spring 和 Quartz 是两个在 Java 开发中非常重要的框架,它们分别用于依赖注入和任务调度。Spring 是一个全方位的 Java 应用开发框架,提供了一系列强大的功能,如 AOP(面向切面编程)、DI(依赖注入)、事务管理等...
将Spring与Quartz结合,我们可以方便地在运行时动态创建和修改定时任务。首先,我们需要在Spring配置文件中声明一个SchedulerFactoryBean,然后定义JobDetail和Trigger,分别表示任务内容和触发条件。JobDetail可以...
Spring和Quartz的集成使得我们可以方便地将定时任务与应用的其他部分无缝连接。Quartz的灵活性和强大功能,配合Spring的便利性,使得开发者可以轻松地创建和管理定时任务,实现如数据同步、日志清理、报表生成等各种...