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 項目地址

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章