Spring整合Quartz框架實現定時任務跑批(Maven完整版)
Quartz is a full-featured, open source job scheduling service that can be integrated with, or
used along side virtually any Java application - from the smallest stand-alone application to
the largest e-commerce system. Quartz can be used to create simple or complex schedules for
executing tens, hundreds, or even tens-of-thousands of jobs;
的電子商務系統。Quartz可以執行上千上萬的任務調度。
Quartz核心的概念:scheduler任務調度、Job任務、Trigger觸發器、JobDetail任務細節
Spring框架提供了對Quartz框架的支持,這對我們來說,方便了很多。我們還是通過Maven工程來演示。1,pom.xml配置文件內容如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.yangcq</groupId> <artifactId>SpringQuartzTest</artifactId> <version>1.0.0</version> <packaging>jar</packaging> <name>SpringQuartzTest</name> <properties> <springframework.version>4.0.6.RELEASE</springframework.version><!-- Spring的版本 --> <quartz.version>2.2.1</quartz.version> <!-- Quartz的版本 --> </properties> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${springframework.version}</version> </dependency> <!-- Spring事務的依賴 --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${springframework.version}</version> </dependency> <!-- 定時任務框架Quartz的依賴--> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>${quartz.version}</version> </dependency> </dependencies> </project>
2,定義我們自己的Job實現類。
Spring框架整合Quartz時,不是直接繼承Job類,而是繼承QuartzJobBean,
我們這裏的一個實現如下:
package com.yangcq.quartz; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.springframework.scheduling.quartz.QuartzJobBean; /** * * @author yangcq * @description 由於Spring提供對Quartz的支持,所以直接使用Spring提供的API * @description 繼承 org.springframework.scheduling.quartz.QuartzJobBean * */ public class EBankJob extends QuartzJobBean { /** * */ private EBankJobBean eBankJobBean; @Override protected void executeInternal(JobExecutionContext arg0) throws JobExecutionException { eBankJobBean.printAnotherMessage(); } public void setEBankJobBean(EBankJobBean eBankJobBean) { this.eBankJobBean = eBankJobBean; } }
這部分代碼就是一個典型的spring註入,實際上調用了eBankJobBean的方法。具體job的執行是在executeInternal
方法裏。
問題一:目前這種方法沒有測試通過,分析一下什麽原因?
問題二:MethodInvokingJobDetailFactoryBean 與 JobDetailBean 的區別,研究Spring源碼
答:
1,QuartzJobBean是Spring框架下的一個抽象類,這個類實現了Quartz的Job接口。我們可以理解為,Spring對Job的
進一步封裝,
public abstract class QuartzJobBean implements Job
2,JobDetailBean也是繼承了Quartz下面的JobDetail接口,這裏為什麽是繼承,本人也感到費解,按說JobDetail是
一個抽象接口,
應該用implements關鍵字實現這個接口,具體代碼如下:
public class JobDetailBean extends JobDetail
3,MethodInvokingJobDetailFactoryBean,這個類為我們設置定時任務,提供了豐富的支持,如下:
private String name;
private String group;
private boolean concurrent;
private String targetBeanName;
private String[] jobListenerNames;
private String beanName;
private ClassLoader beanClassLoader;
private BeanFactory beanFactory;
private JobDetail jobDetail;
package com.yangcq.quartz;
/**
*
* @author yangcq
*
*/
public class EBankJobBean {
public void printAnotherMessage(){
System.out.println("CronTriggerBean 調用的定時任務...");
}
}
因為是要將這些任務通過spring的配置文件來拼接到一起,我們來看看具體的配置文件該怎麽設置。
在spring裏,如果我們要執行一個計劃任務,需要定義一個JobDetail,用它來封裝我們具體執行的任務。結合前面純quartz的示例,
我們發現它們其實本質上是一樣的。這裏的定義如下:
spring默認提供了一個叫MethodInvokingJobDetailFactoryBean,我們需要將定義好的對象和需要調用的方法傳給它。
這裏對應的是一種類型的jobDetail定義。對應的myBean定義如下:
package com.yangcq.quartz;
/**
*
* @author yangcq
* @description SimpleTriggerFactoryBean 調用的定時任務
*/
public class MyJobBean {
public void printMessage() {
System.out.println("SimpleTriggerFactoryBean 調用的定時任務...");
}
}
OK,下面寫一個測試類,進行測試
package com.yangcq.quartz;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
*
* @author yangcq
* @description 啟動定時任務main方法
*
*/
public class StartUpQuartzJobs {
static final Log log = LogFactory.getLog(StartUpQuartzJobs.class); // 日誌
public static void main(String args[]) throws Exception {
log.info("開始啟動定時任務 ...");
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
log.info("定時任務啟動成功...");
}
}
接下來就是關鍵部分了,Spring核心配置文件的的配置,配置文件applicationContext.xml配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- Bean頭部 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<!-- 啟動包掃描功能,以便註冊帶有@Controller、@Service、@repository、@Component等註解的類成為spring的bean -->
<context:component-scan base-package="com.yangcq.quartz" />
<bean id="myJobBean" class="com.yangcq.quartz.MyJobBean"></bean>
<bean id="eBankJobBean" class="com.yangcq.quartz.EBankJobBean"></bean>
<bean id="simpleJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myJobBean" />
<property name="targetMethod" value="printMessage" />
</bean>
<!-- 這種封裝的方式很簡單,就是我定義了一個對象和它對應的方法。如果我們需要將它們封裝成一個job了,只要把類的名字和 -->
<!-- 對應的方法傳進去就可以了。除了上述的JobDetail構造方式,還要一種更復雜一些,它的定義如下: -->
<!-- 這裏因為要用到一些對象的引用,對這些對象或者參數的傳遞可以通過jobDataMap來處理。 -->
<bean name="complexJobDetail" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="eBankJobBean" />
<property name="targetMethod" value="printAnotherMessage" />
</bean>
<!-- Spring提供了2中觸發器:SimpleTriggerBean 和 CronTriggerBean -->
<!-- Trigger觸發器 :從第1秒開始,每3秒執行一次 -->
<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
<property name="jobDetail" ref="simpleJobDetail" />
<property name="startDelay" value="1000" />
<property name="repeatInterval" value="3000" />
</bean>
<!-- Trigger觸發器 :從第1秒開始,每5秒執行一次 -->
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
<property name="jobDetail" ref="complexJobDetail" />
<property name="cronExpression" value="0/5 * * * * ?" />
</bean>
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="jobDetails">
<list>
<ref bean="simpleJobDetail" />
<ref bean="complexJobDetail" />
</list>
</property>
<property name="triggers">
<list>
<ref bean="simpleTrigger" />
<ref bean="cronTrigger" />
</list>
</property>
</bean>
</beans>
啟動程序以後,控制臺輸出如下:
log4j:WARN No appenders could be found for logger (com.yangcq.quartz.StartUpQuartzJobs).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
SimpleTriggerFactoryBean 調用的定時任務...
CronTriggerBean 調用的定時任務...
SimpleTriggerFactoryBean 調用的定時任務...
CronTriggerBean 調用的定時任務...
SimpleTriggerFactoryBean 調用的定時任務...
總結
在這兩個示例裏,我們首先通過一個純手工的過程來完成一個任務調度的示例。它的主要步驟為
1.定義job
- 定義trigger
- 定義scheduler來拼接。
在後續使用spring的示例裏,其實也是這麽一個步驟,只不過spring提供了一些實現的支持,需要在配置文件裏指定
不同的jobDetail類型和trigger類型。
Spring整合Quartz框架實現定時任務跑批(Maven完整版)