集成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>
參考:
Spring 4 + Quartz Scheduler Integration Example,這個很好
Spring 4 + Quartz 2 Scheduler Integration Annotation Example using JavaConfig