spring和Quartz 集成

集成Spring+ quartz 分为四步

第一步 POM.XML 添加spring+quartz依赖

 <!-- Spring start-->

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-beans</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
        </dependency>
        <!-- Spring 和 quartz 集成需要的jar 包 spring-context-support spring-tx-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
        </dependency>
        <!-- Spring stop-->
        <!-- quartz 定时任务开始-->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.2.1</version>
            <exclusions>
                <exclusion>
                    <artifactId>slf4j-api</artifactId>
                    <groupId>org.slf4j</groupId>
                </exclusion>
                <exclusion>
                    <groupId>c3p0</groupId>
                    <artifactId>c3p0</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
            <version>2.2.1</version>
        </dependency>
        <!-- quartz 定时任务结束-->

第二步 定义Spirng和quartz整合的Job 有两个类型的Job:MethodInvokingJobDetailFactoryBean 和 JobDetailFactoryBean

JobDetailFactoryBean

下面配置一个job,继承QuartzJobBean类,调度时候将回调executeInternal方法。我们的调度逻辑写在这个方法里面。jobDataMap 参数提供向jobBean传递参数的功能。

<!-- 定义作业任务Bean JobDetailFactoryBean 来管理作业任务;
        当你需要传递数据给Job 时候使用这个JobBean.-->
        <bean id="jobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
                <!--
                    参考源码,我们可以看到属性jobClass为Class类型,所以不能使用ref来引用一个bean,否则就会因为不能将bean转换为Class类型而出现异常。
                    <property name="jobClass" ref="simpleJob"/>
                    必须使用value对jobClass赋值。
                    <property name="jobClass" value="common.quartz.spring.task002.SimpleJob"/>
                -->
                <property name="jobClass" value="common.quartz.spring.task002.SimpleJob"/>
                <!-- 这里设置的jobDataAsMap可以传递一些参数给作业任务 -->
                <property name="jobDataAsMap">
                        <map>
                                <entry key="name" value="vincent"/>
                                <entry key="copyright" value="PLCC"/>
                                <entry key="key3" value="987"/>
                                <entry key="anotherBean" value-ref="anotherBean"/>
                        </map>
                </property>
                <property name="durability" value="true"/>
                <property name="group" value="jobDetail-jobname-group"/>
                <property name="name" value="jobDetail-jobname"/>
        </bean>

SimpleJob

package common.quartz.spring.task002;

import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;
import org.quartz.PersistJobDataAfterExecution;
import org.springframework.scheduling.quartz.QuartzJobBean;

/**
 * batch-parent.common.quartz.spring <br/>
 * Created by PengRong on 2018/1/12. <br/>
 * Spring + Quartz 集成后,使用JobDetailFactoryBean来管理作业任务时,我们的作业任务实现类需要继承QuartzJobBean类,并覆盖其executeInternal方法。
 * 这个Quartz 作业Bean 有点不友好
 * @author PengRong <br/>
 * @Description TODO(${END})
 * @ClassName: ${CLASS}
 * @since 2018-01-12 16:19 <br/>
 */
//@Component("simpleJob") Quartz 调度任务通过class 反射调用的。

/**
 * 如果你需要持久化 JobDataMap里面的数据你就需要PersistJobDataAfterExecution注解Job;
 * 如果多个触发器调度Scheduling同一个job,为了避免竞争冲突。使用DisallowConcurrentExecution 注解Job
  */
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
public class SimpleJob extends QuartzJobBean {
    public static final String COUNT = "key3";
    private AnotherBean anotherBean;

    public void setAnotherBean(AnotherBean anotherBean) {
        this.anotherBean = anotherBean;
    }

    /**
     * SimpleJob 任务Job 类
     * @param context
     * @throws JobExecutionException
     */
    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {

        JobKey key = context.getJobDetail().getKey();
        //job 唯一标识符
        System.out.println("时间是"+new SimpleDateFormat("yyyy-MM-dd- HH-时-mm-分-ss-秒-").format(new Date())+"key: "+key);
        JobDataMap map = context.getJobDetail().getJobDataMap();
        String name = map.getString("name");
        int count=map.getInt(COUNT);
        System.out.print("quartzJob task Spring....." + name+"\tkey: "+key+"\t "+count++);
        map.put(COUNT,count);
        anotherBean.printAnotherMessage();
    }
}

anotherBean

package common.quartz.spring.task002;

import org.springframework.stereotype.Component;

/**
 * @Package: common.quartz.spring.task002 <br/>
 * @Description: 这个类设置成被SimpleJob 引用从而被调用的Job。 <br/>
 * @author: PengRong <br/>
 * @Date: Created in 2018/1/14 12:40 <br/>
 * @Company: PLCC <br/>
 * @Copyright: Copyright (c) 2017 <br/>
 * @Version: 1.0 <br/>
 * @Modified By: <br/>
 * @Created by PengRong on 2018/1/14. <br/>
 */
@Component("anotherBean")
public class AnotherBean {
        public void printAnotherMessage(){
                System.out.println("I am called by Quartz jobBean using CronTriggerFactoryBean");
        }
}

MethodInvokingJobDetailFactoryBean

这个类很简单,调度时候调用exampleJob的execute方法。

 <!-- 定义作业任务 Bean MethodInvokingJobDetailFactoryBean -->
        <!--
            如果两个触发器触发调度同一个作业,那么可能造成资源竞争。
            将作业类实现StatefulJob接口就可以避免这种情况。
            将concurrent设置为false可以避免并发的发生。
        -->
        <!-- 使用MethodInvokingJobDetailFactoryBean来创建作业对象
            下面这个Job 配置就是调用 ExampleJob 类的execute 方法。ExampleJob 只是一个简单方法。
         -->
        <bean id="methodInvokingJobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
                <!-- 目标对象,指的是作业任务的实现类 -->
                <property name="targetObject" ref="exampleJob"/>
                <!-- 目标方法,指的是指定实现类中的哪个方法作为调度时的执行方法;无参数-->
                <property name="targetMethod" value="execute"/>
                <!-- 是否并发 -->
                <property name="concurrent" value="false"/>
                <!-- 设置job 的名字和组名 -->
                <property name="name" value="spring-quartz-methodInvoking-method"/>
                <property name="group" value="spring-quartz-methodInvoking-method-group"/>
        </bean>

exampleJob

package common.quartz.spring.task002;

import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * batch-parent.common.quartz.spring.task002 <br/>
 * Created by PengRong on 2018/1/12. <br/>
 * Spring + quartz 集成后 任务作业Bean :MethodInvokingJobDetailFactoryBean 的作业类。不用继承任何类和接口
 * @author PengRong <br/>
 * @Description TODO(${END})
 * @ClassName: ${CLASS}
 * @since 2018-01-12 16:36 <br/>
 */
@Component("exampleJob")
public class ExampleJob {
    public void execute(){
        System.out.println("现在是"+new SimpleDateFormat("yyyy年MM月dd日 HH时mm分ss秒").format(new Date())+"\tI am called by MethodInvokingJobDetailFactoryBean using SimpleTriggerFactoryBean");
    }
}

第三步 配置触发器,定义了调度的时间规则

MethodInvokingJobDetailFactoryBean 的触发器


        <!-- 触发器 simpleTrigger; 配置了作业信息; 下面配置了一个初始延迟 5秒,然后间隔3秒调度任务。-->
        <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
                <!-- 这里的JobDetail指的就是我们配置的作业任务的bean -->
                <property name="jobDetail" ref="methodInvokingJobDetailFactoryBeanExample" />
                <!-- 启动后延迟5秒开始调度任务 -->
                <property name="startDelay" value="5000"></property>
                <!-- 每3秒重复一次 -->
                <property name="repeatInterval" value="3000"></property>
        </bean>

jobDetailFactoryBeanExample的触发器


<!-- 触发器 cronTrigger ;
         定义一个在周末每隔5秒调用一次的任务的触发器-->
        <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
                <!-- 这里的JobDetail指的就是我们配置的作业任务的bean -->
                <property name="jobDetail" ref="jobDetailFactoryBeanExample"/>
                <!--cronExpression,cron表达式-->
                <property name="cronExpression" value="0/5 * * ? * SAT-SUN"/>
        </bean>

定义调度器

 <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
                <property name="triggers">
                        <list>
                                <ref bean="simpleTrigger"></ref>
                                <ref  bean="cronTrigger"/>
                        </list>
                </property>
                <!-- 上面触发器已经关联了 任务Job, 所以这个调度器里面可以不用设置任务Job -->
               <!-- <property name="jobDetails">
                    <list>
                        <ref bean="jobDetailFactoryBeanExample"/>
                        <ref bean="methodInvokingJobDetailFactoryBeanExample"/>
                    </list>
                </property>-->
        </bean>

最后一步测试:

package common.quartz.spring.task002; 

import common.BaseTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/** 
* SpringQuartzJob Tester.
* 
* @author <PengRong> 
* @since  
* @version 1.0 
*/ 
public class SpringQuartzJobTest extends BaseTest{

@Before
public void before() throws Exception { 
} 

@After
public void after() throws Exception { 
} 

/** 
* 
* Method: execute() 
* 
*/ 
@Test
public void testExecute() throws Exception {
         System.out.println("Spring 和 Quartz 框架集成 测试.");
         Thread.sleep(1000000);
}


} 

配置文件(src/main/resources/spring/quartz/spring-quartz.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd">
        <!-- Quartz 集成Spring 配置-->
        <!-- 第一步:配置Quartz 和Spring 集成后的 作业任务配置 -->
        <!-- 定义作业任务Bean JobDetailFactoryBean 来管理作业任务;
        当你需要传递数据给Job 时候使用这个JobBean.-->
        <bean id="jobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
                <!--
                    参考源码,我们可以看到属性jobClass为Class类型,所以不能使用ref来引用一个bean,否则就会因为不能将bean转换为Class类型而出现异常。
                    <property name="jobClass" ref="simpleJob"/>
                    必须使用value对jobClass赋值。
                    <property name="jobClass" value="common.quartz.spring.task002.SimpleJob"/>
                -->
                <property name="jobClass" value="common.quartz.spring.task002.SimpleJob"/>
                <!-- 这里设置的jobDataAsMap可以传递一些参数给作业任务 -->
                <property name="jobDataAsMap">
                        <map>
                                <entry key="name" value="vincent"/>
                                <entry key="copyright" value="PLCC"/>
                                <entry key="key3" value="987"/>
                                <entry key="anotherBean" value-ref="anotherBean"/>
                        </map>
                </property>
                <property name="durability" value="true"/>
                <property name="group" value="jobDetail-jobname-group"/>
                <property name="name" value="jobDetail-jobname"/>
        </bean>

        <!-- 定义作业任务 Bean MethodInvokingJobDetailFactoryBean -->
        <!--
            如果两个触发器触发调度同一个作业,那么可能造成资源竞争。
            将作业类实现StatefulJob接口就可以避免这种情况。
            将concurrent设置为false可以避免并发的发生。
        -->
        <!-- 使用MethodInvokingJobDetailFactoryBean来创建作业对象
            下面这个Job 配置就是调用 ExampleJob 类的execute 方法。ExampleJob 只是一个简单方法。
         -->
        <bean id="methodInvokingJobDetailFactoryBeanExample" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
                <!-- 目标对象,指的是作业任务的实现类 -->
                <property name="targetObject" ref="exampleJob"/>
                <!-- 目标方法,指的是指定实现类中的哪个方法作为调度时的执行方法;无参数-->
                <property name="targetMethod" value="execute"/>
                <!-- 是否并发 -->
                <property name="concurrent" value="false"/>
                <!-- 设置job 的名字和组名 -->
                <property name="name" value="spring-quartz-methodInvoking-method"/>
                <property name="group" value="spring-quartz-methodInvoking-method-group"/>
        </bean>
        <!-- 第二步:配置Quartz 和Spring 集成后的 触发器配置;触发器定义了调度器调度你的Job 的时间, -->

        <!-- 触发器 simpleTrigger; 配置了作业信息; 下面配置了一个初始延迟 5秒,然后间隔3秒调度任务。-->
        <bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerFactoryBean">
                <!-- 这里的JobDetail指的就是我们配置的作业任务的bean -->
                <property name="jobDetail" ref="methodInvokingJobDetailFactoryBeanExample" />
                <!-- 启动后延迟5秒开始调度任务 -->
                <property name="startDelay" value="5000"></property>
                <!-- 每3秒重复一次 -->
                <property name="repeatInterval" value="3000"></property>
        </bean>
        <!-- 触发器 cronTrigger ;
         定义一个在周末每隔5秒调用一次的任务的触发器-->
        <bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
                <!-- 这里的JobDetail指的就是我们配置的作业任务的bean -->
                <property name="jobDetail" ref="jobDetailFactoryBeanExample"/>
                <!--cronExpression,cron表达式-->
                <property name="cronExpression" value="0/5 * * ? * SAT-SUN"/>
        </bean>
        <!-- 第三步:配置Quartz 和Spring 集成后的 调度工厂配置; 组合JobDetails and triggers  -->
        <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
                <property name="triggers">
                        <list>
                                <ref bean="simpleTrigger"></ref>
                                <ref  bean="cronTrigger"/>
                        </list>
                </property>
                <!-- 上面触发器已经关联了 任务Job, 所以这个调度器里面可以不用设置任务Job -->
               <!-- <property name="jobDetails">
                    <list>
                        <ref bean="jobDetailFactoryBeanExample"/>
                        <ref bean="methodInvokingJobDetailFactoryBeanExample"/>
                    </list>
                </property>-->
        </bean>
</beans>

Spring 容器文件 Application.xml(src/main/resources/spring/Application.xml)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
                        http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
                        http://www.springframework.org/schema/context
                        http://www.springframework.org/schema/context/spring-context-4.0.xsd"
       default-autowire="byName" default-lazy-init="false">
    <!-- 采用注解的方式配置bean -->
    <context:annotation-config />

    <!-- 配置要扫描的包 -->
    <context:component-scan base-package="common"/>
    <!-- 该 BeanPostProcessor 将自动对标注 @Autowired 的 Bean 进行注入 -->
    <bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>
    <!--
        <context:component-scan base-package="com.imodule" />  -->
    <!--<context:component-scan base-package="com.generated.lifepro" />-->

    <!-- 引入资源 -->
    <!--<import resource="spring-mybatis.xml" />-->

    <!--    <import resource="hydra-config.xml"/> -->
    <!-- 配置spring-batch
    <import resource="spring-batch.xml"/>
    <import resource="dubbo-consumer.xml"/> -->
    <!-- 配置Spring-quartz.xml 定时调度器 -->
    <import resource="quartz/spring-quartz.xml"/>
    <!-- 获取数据库配置属性, 这种方式配置的属性 不能再代码中获取。-->
   <!-- <context:property-placeholder location="mysql/mysql-db.properties"/>-->

</beans>

参考:

Quartz与Spring的整合使用

Spring 4 + Quartz Scheduler Integration Example,这个很好

Spring 4 + Quartz 2 Scheduler Integration Annotation Example using JavaConfig

github 项目地址

猜你喜欢

转载自blog.csdn.net/jq_ak47/article/details/79056763