`
QING____
  • 浏览: 2250654 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Spring与Quartz Cluster备忘

    博客分类:
  • JAVA
 
阅读更多

    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&amp;characterEncoding=UTF-8&amp;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项目中能够得以解决。否则开发者需要补充太多东西,才能将此架构完善。

分享到:
评论

相关推荐

    Java_Spring与Quartz的整合

    以下将详细介绍如何进行Spring与Quartz的整合。 1. **集成步骤** - 添加依赖:首先,确保在项目中添加了Spring和Quartz的相关库。如果是Maven项目,可以在pom.xml文件中加入对应的依赖。 - 配置Quartz:在Spring...

    spring+quartz demo

    Spring 提供了与 Quartz 集成的模块,使得在 Spring 应用程序中使用 Quartz 更加便捷,包括 Job 实例的管理、触发器的配置以及对 Quartz Scheduler 的控制。 在这个 "spring+quartz demo" 中,我们可以学习到如何将...

    quartz和spring-quartz

    Spring-Quartz的集成则将这些概念与Spring的IoC(Inversion of Control)容器相结合,提供了更好的依赖注入支持。以下是一些关键点: 1. **Bean集成**: Spring可以自动将Job实例作为Spring Bean管理,这样你就可以...

    spring2与quartz在Web整合

    在将 Spring 2 与 Quartz 整合到 Web 应用中时,主要涉及以下几个关键知识点: 1. **Spring 2 的核心概念**:Spring 2 提供了 IoC(Inversion of Control,控制反转)和 AOP(Aspect-Oriented Programming,面向切...

    Spring_QuartZDemo

    在Spring的配置文件中,我们首先需要定义一个`SchedulerFactoryBean`,它是Spring与Quartz的桥梁。例如: ```xml &lt;bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"&gt; ...

    spring+quartz使用jar包

    1. **Spring与Quartz的整合**:Spring 提供了对Quartz的集成支持,通过`org.springframework.scheduling.quartz`包中的类,如`SchedulerFactoryBean`和`ThreadPoolTaskExecutor`,可以轻松地将Quartz纳入Spring的...

    Spring+quartz相关jar包.rar

    当 Spring 与 Quartz 结合使用时,Spring 可以通过其强大的容器管理和配置能力,将 Quartz 集成到应用程序中。例如,Spring 提供了 `org.springframework.scheduling.quartz` 包,该包包含了一些用于配置 Quartz 的...

    关于spring中quartz的配置

    在Spring框架中集成Quartz是一款常见的任务调度解决方案,它允许开发者在应用中安排定时任务的执行。Quartz是一个开源的作业调度框架,可以用来在Java应用程序中安排复杂的作业任务。以下将详细介绍如何在Spring中...

    Spring+Quartz2

    在压缩包 "Spring3+Quartz2" 中,可能包含的是一个 Spring 3.x 版本与 Quartz2 结合使用的示例项目,你可以通过解压并运行该项目,学习如何在实际项目中实现类似的功能。记得根据你的具体需求进行适当的修改和配置。

    Spring-quartz-demo Spring4.1.6 + quartz2.2.1

    本项目来源与网络,本人对项目...直接通过mvn 倒入项目,在Spring-quartz-demo\src\main\webapp\sql 有sql 建立数据库,表 启动tomcat 直接访问http://localhost:8080/Spring-quartz-demo/task/taskList.htm 就可以使用

    spring整合quartz文档

    Spring 提供了与 Quartz 的无缝集成,允许你通过 Spring 的配置文件来管理 Job 和 Trigger。这包括 Job 的声明、Trigger 的设置以及与 Spring Bean 的关联。通过 Spring,你可以利用其强大的依赖注入(DI)和管理...

    SpringQuartz的使用文档

    SpringQuartz是一个强大的任务调度框架,它在Java应用程序中用于自动化执行特定任务,如定时生成文件、统计数据或执行后台清理工作。Quartz是开源的,具有高度灵活的调度功能,能够根据预定义的时间表触发任务,同时...

    spring-quartz定时设置详细说明

    Spring 和 Quartz 是两个在 Java 开发中非常重要的框架。Spring 是一个全面的后端开发框架,而 Quartz 是一个强大的任务调度库。将它们结合使用,我们可以实现基于 Spring 的应用程序中的定时任务管理。以下是对 ...

    spring 集成quartz 用数据库实现quartz的集群

    【Spring集成Quartz定时任务与数据库实现集群详解】 在企业级应用中,定时任务的管理是必不可少的一部分,Spring框架提供了与Quartz的集成,使得我们可以方便地创建和管理定时任务。Quartz是一款强大的、开放源代码...

    spring的quartz使用实例

    Quartz是一个开源的作业调度框架,而Spring通过提供一个简洁的API使得与Quartz的集成变得简单。以下是对Spring整合Quartz使用实例的详细说明: 1. **Quartz简介** Quartz是一个强大的、完全开源的作业调度框架,它...

    spring+quartz需要的4个jar包 不需要6个

    在Java开发领域,Spring框架和Quartz库是两个非常重要的组件。Spring是一个全面的企业级应用框架,它提供了依赖注入、AOP(面向切面编程)、MVC(模型-视图-控制器)等特性,帮助开发者构建高效、灵活的Java应用程序...

    Spring+Quartz 集群

    在IT行业中,Spring框架是Java企业级应用开发的首选,而Quartz则是一个强大的任务调度库,常用于实现定时任务。本篇文章将深入探讨如何在Spring环境中集成Quartz以构建一个高可用的集群。 首先,我们需要理解Spring...

    spring+quartz定时小例子

    Spring 和 Quartz 是两个在 Java 开发中非常重要的框架,它们分别用于依赖注入和任务调度。Spring 是一个全方位的 Java 应用开发框架,提供了一系列强大的功能,如 AOP(面向切面编程)、DI(依赖注入)、事务管理等...

    spring+quartz动态定时任务创建 +mybatis

    将Spring与Quartz结合,我们可以方便地在运行时动态创建和修改定时任务。首先,我们需要在Spring配置文件中声明一个SchedulerFactoryBean,然后定义JobDetail和Trigger,分别表示任务内容和触发条件。JobDetail可以...

    Spring+Quartz定时任务学习文档+实例+jar包

    Spring和Quartz的集成使得我们可以方便地将定时任务与应用的其他部分无缝连接。Quartz的灵活性和强大功能,配合Spring的便利性,使得开发者可以轻松地创建和管理定时任务,实现如数据同步、日志清理、报表生成等各种...

Global site tag (gtag.js) - Google Analytics