Spring 3 调度器示例 —— JDK 定时器和 Quartz 展示 已翻译 100%

oschina 投递于 2013/10/21 22:39 (共 10 段, 翻译完成于 10-22)
阅读 8819
收藏 164
11
加载中

Spring框架提供了执行和调度任务的抽象,支持线程池或者在应用服务器环境中代理给CommonJ. Spring也集成了支持使用JDK Timer和Quartz调度库提供的Quartz Scheduler来实现任务调度的类.两种调度器通过分别引用可选的Timer或者org.quartz.Trigger实例的工厂Bean来进行设置. 另外,还有一个可以同时满足Timer和Quartz Scheduler的类允许我们调用一个存在的目标对象的方法.

在这篇教程中,我们将向你展示在Spring中如何实现一个JDK Timer的例子,然后我们将使用Quartz Scheduler来丰富这个例子.

我们首选的开发环境是Eclipse. 我们使用的Eclipse版本是Eclipse Juno (4.2)同时集成了版本为 3.1.0的Maven插件. 你可以从这里下载Eclipse,然后从这里下载Maven插件.Eclipse中Maven插件的安装不在本教程的范围之内,我们将不在此进行讨论. 我们还用到了Spring3.2.3和JDK 7_u_21.

让我们开始吧.

一条大河波浪宽
翻译于 2013/10/22 22:56
1

1. 创建一个新的maven项目

Go to File -> Project ->Maven -> Maven Project.

New-Maven-Project

在 “Select project name and location”向导页, 选择 “Create a simple project (skip archetype selection)”这个选项, 其他默认,点击“Next”.

Maven-Project-Name-Location

在 “Enter an artifact id” 这个页面, 你可以定义你的项目名称和主包. 我们将设置 “Group Id” 的值为"com.javacodegeeks.snippets.enterprise"以及 “Artifact Id” 的值为"springexample". 这亮相是项目的所在包"com.javacodegeeks.snippets.enterprise.springexample"和项目名称"springexample".点击 “Finish”退出向导,会自动简历项目.

Configure-Maven-Project

Maven 项目结构:

Maven-project-structure

It consists of the following folders:
  • /src/main/java 文件夹,包含程序源文件信息 ,
  • /src/test/java 文件夹是所有测试信息contains all source files for unit tests,
  • /src/main/resources文件夹放置所有配置文件
  • /target 文件夹 放置编译和打包好的文件
  •  pom.xml是项目对象模型(POM)文件. 这一个文件包含项目所有的相关配置信息


你要爪子
翻译于 2013/10/21 23:30
1

2. 添加Spring 3.2.3依赖

  • POM编辑器的 “Overview” 页中,定位到“Properties”一节,进行下列变更:
    创建一个新的名为org.springframework.version的属性把其值设置为3.2.3.RELEASE.
  • 切换到“Dependencies”页上,创建下面的依赖(你需要在该页的“Dependency Details”部分中填写“GroupId”, “Artifact Id”和“Version”等字段):
    Group Id : org.springframework Artifact Id : spring-web Version : ${org.springframework.version}

或者,你也可以直接在Maven的pom.xml文件中添加Spring依赖,即直接在POM编辑器的“Pom.xml”页上进行编辑,如下所示:
 
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.javacodegeeks.snippets.enterprise</groupId>
	<artifactId>springexample</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
	</dependencies>

	<properties>
		<spring.version>3.2.3.RELEASE</spring.version>
	</properties>
</project>

正如你所见,Maven通过声明的方式来管理包依赖。一个本地库会被创建(默认在{user_home}/.m2 目录中),所有需要的类库会从共有库中下载下来放置到本地库中。进而在其内部 – 库依赖关系会被自动的处理和控制。

lwei
翻译于 2013/10/22 14:30
2

3.添加 Quartz 依赖

在项目的pom.xml文件中添加 Quartz 依赖,下面是添加后的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.javacodegeeks.snippets.enterprise</groupId>
	<artifactId>springexample</artifactId>
	<version>0.0.1-SNAPSHOT</version>

	<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>

		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>3.1.2.RELEASE</version>
		</dependency>

		<!-- 这里是 Quartz 框架依赖-->
		<dependency>
			<groupId>org.quartz-scheduler</groupId>
			<artifactId>quartz</artifactId>
			<version>1.8.6</version>
		</dependency>
	</dependencies>
	<properties>
		<spring.version>3.2.3.RELEASE</spring.version>
	</properties>
</project>

4. 在Spring 中使用JDK 自带的定时任务

4.1 创建一个简单的任务

下面的MyTask.java 是个简单的可以执行的任务

MyTask.java

package com.javacodegeeks.snippets.enterprise;

public class MyTask {
	public void sayHello() {
		System.out.println("Hello !!! ");
	}
}
l
翻译于 2013/10/22 10:54
1

4.2 在applicationContext.xml中配置Scheduler和Timer

Spring 使用自己实现的Task取代了JDK中的TimerTask,Spring的Task是可以被定时调用或者通过Timer来重复调用的,它就是org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean。它也提供了对于JDK Timer的一个实现,它是一个后台线程用来调度任务的工具类,这个类就是org.springframework.scheduling.timer.ScheduledTimerTask。
另外,还定义了一个TimerFactoryBean, 来启动计划任务的执行. 它是一个工厂Bean,它设置了一个暴露给其他bean引用的Timer. 它允许注册ScheduledTimerTask,在容器启动的时候开启Timer然后在容器销毁的时候将它取消。

需要执行计划任务的时候,我们需要做的就是在applicationContext.xml文件中定义上面所有提到过的类. 我们在myTask bean中指定MyTask.java类. 我们也需要定义schedulerBean, 它引用TimerTask类. 它有两个属性需要配置. targetObject的值引用我们自己实现的任务bean,也就是myTask. targetMethod属性的值是需要被计划执行的任务方法.

一条大河波浪宽
翻译于 2013/10/22 21:30
1

timerTask这个bean是个Timer类型的bean。它有一个timerTask属性,我们可以通过它设置对上面定义好的名为timerTask的bean的引用。这里我们可以使用delay参数来配置第一次开始任务前的延时时间,单位是毫秒。我们也可以使用period参数来设置重复执行任务之间的间隔,单位也是毫秒。我们把它配置成每5秒钟执行一次,首次延时1秒钟。

TimerFactoryBean也定义在applicationContext.xml中。我们可以使用FactoryBean创建的Timer通过scheduledTimerTask参数,来注册一系列ScheduledTimerTask对象。这里,我们注册了定义好的timerTask。

applicationContext.xml

<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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">

  
 <bean id="myTask" class="com.javacodegeeks.snippets.enterprise.MyTask" />
 
 <bean id="schedulerTask" 
  class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean">
	<property name="targetObject" ref="myTask" />
	<property name="targetMethod" value="sayHello" />
</bean>

<bean id="timerTask"
	class="org.springframework.scheduling.timer.ScheduledTimerTask">
	<property name="timerTask" ref="schedulerTask" />
	<property name="delay" value="1000" />
	<property name="period" value="5000" />
</bean>

<bean class="org.springframework.scheduling.timer.TimerFactoryBean">
	<property name="scheduledTimerTasks">
		<list>
			<ref local="timerTask" />
		</list>
	</property>
</bean>
</beans>
lwei
翻译于 2013/10/22 13:54
1

5 Quartz调度器

5.1 Quartz调度器任务

为了使用Quartz调度器来丰富我们的例子,首先我们必须设置一个Quartzs调度器任务。可以用两种方式实现这一工作。第一种方式是在applicationContext.xml中把调度任务定义成Spring的一个bean。这个bean可以是一个org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean类,有两个配置参数targetObject和targetMethod,就像我们在上一步中所做的一样。不过,让我们来尝试一个更加复杂的调度器吧。我们仅需创建一个类来继承org.springframework.scheduling.quartz.QuartzJobBean,就可以实现我们自己的两个调度器。MyTask.java可以通过一个setter方法传递给调度器。随后,任务里的方法会在继承自QuartzJobBean的调度任务的executeInternal(JobExecutionContext context)方法中被调用。

QuartzJob.java

package com.javacodegeeks.snippets.enterprise.quartz;

import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.scheduling.quartz.QuartzJobBean;

import com.javacodegeeks.snippets.enterprise.MyTask;

public class QuartzJob extends QuartzJobBean {
	
	private MyTask myTask;

	public void setMyTask(MyTask myTask) {
		this.myTask = myTask;
	}

	protected void executeInternal(JobExecutionContext context)
		throws JobExecutionException {
		myTask.sayHello(); 
	}
}
lwei
翻译于 2013/10/22 13:41
1

5.2 Quartz触发器

现在我们必须要来定义运行调度任务的Quartz触发器了。Quartz提供了两个类来实现触发器部分。在org.springframework.scheduling.quartz.SimpleTriggerBean中我们可以设置startTime,endTime和intervals来运行任务,而在org.springframework.scheduling.quartz.CronTriggerBean则支持UNIX的cron表达式来指定任务运行的时间。两种触发器类型都被定义成Spring的bean,而且两者都提供了一个jobDetail参数来设置对调度任务的引用。

还有一个配置工作是创建一个SchedulerFactoryBean,它可以整合调度任务和触发器。所以两个bean都被包含在SchedulerFactoryBean的定义中。

在applicationContext.xml中我们定义了所有的的bean,包括调度任务、触发器和SchedulerFactoryBean。

applicationContext.xml

<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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd">

  
 <bean id="myTask" class="com.javacodegeeks.snippets.enterprise.MyTask" />

<!-- quartz -->
	<bean name="quartzJob" class="org.springframework.scheduling.quartz.JobDetailBean">
		<property name="jobClass" value="com.javacodegeeks.snippets.enterprise.quartz.QuartzJob" />
		<property name="jobDataAsMap">
		  <map>
			<entry key="myTask" value-ref="myTask" />
		  </map>
		</property>
	</bean>
	
	<bean id="simpleTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean"> 
		<property name="jobDetail" ref="quartzJob" />
		<property name="repeatInterval" value="5000" />
		<property name="startDelay" value="1000" />
	</bean>
 
	<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
 		<property name="jobDetail" ref="quartzJob" />
		<property name="cronExpression" value="0/5 * * * * ?" /> 
	</bean>
 
	<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
		<property name="jobDetails">
			<list>
				<ref bean="quartzJob" />
			</list>
		</property> 
		<property name="triggers">
			<list>
				<ref bean="cronTrigger" />
			</list>
		</property>
	</bean>
</beans>
lwei
翻译于 2013/10/22 14:06
1

注意,我们添加的两个触发器的实现,在SchedulerFactoryBean中只使用了其中一个。cronTrigger是org.springframework.scheduling.quartz.CronTriggerBean类型的实现,而simpleTrigger是org.springframework.scheduling.quartz.SimpleTriggerBean类型的实现。在SchedulerFactoryBean类型的bean的triggers参数中设置了对cronTrigger的引用,而在jobDetails参数中设置了对调度任务的引用。

需要注意的另外一件事是,名为quartzJob的bean的定义。这里通过一个参数把Quartz任务类设定为org.springframework.scheduling.quartz.JobDetailBean类。该类有一个jobDataAsMap参数,任务会在这里进行注册。

lwei
翻译于 2013/10/22 14:20
1

6. 运行应用

在App.java类里,我们装载了applicationContext.xml文件并使运行应用程序的线程休眠30秒后再关闭上下文。一旦上下文被打开,任务就会像上面安排的那样开始运行。sayHello()方法每5秒钟被调用一次,两个案例都是。

App.java

package com.javacodegeeks.snippets.enterprise;

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {

	public static void main(String[] args) throws InterruptedException {
		ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		Thread.sleep(30000);
		context.close();
	}

}

这是关于Spring 3 Scheduler的两个实现JDK TimerQuartz的一个例子。

可以下载该教程的Eclipse项目 : SpringSchedulerQuartzExample.zip

lwei
翻译于 2013/10/22 09:29
1
本文中的所有译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接。
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。
加载中

评论(12)

Onegoleya
Onegoleya
你这样子不会判断之前的进程是否已经跑完啊 ~ 只是实现了定时
吴峻申
吴峻申

引用来自“吴峻申”的评论

我们以前用quartz做的是可以在前台页面设置时间间隔,而且马上生效,不需要重启tomcat就能实现热部署,热运行~

引用来自“DolphinBoy”的评论

如何实现的啊? 这么牛掰!

我要找一下,这段代码可以在oschina共享。我依稀记得前台设置的时间间隔信息是存放在数据库里的。

Skqing
Skqing

引用来自“吴峻申”的评论

我们以前用quartz做的是可以在前台页面设置时间间隔,而且马上生效,不需要重启tomcat就能实现热部署,热运行~

如何实现的啊? 这么牛掰!

d
dizh
鞋的不错啊。
LianyouCQ
LianyouCQ
刚好准备在项目中使用spring3.25 和 quartz 2.x, 不错
吴峻申
吴峻申
我们以前用quartz做的是可以在前台页面设置时间间隔,而且马上生效,不需要重启tomcat就能实现热部署,热运行~
DW_GYT
DW_GYT
学习的意义更大,不错
小湛同学
小湛同学
1、楼主做事情不够细致认真
2、版本号管理认识不够
3、分享的理念是值得提倡的
4、实现的思路不够清爽简单

鉴定完毕
fox_lht
fox_lht
实例中有很多错误,例如:前面是 ${org.springframework.version},后面变成${spring.version},依赖库也不对,至少有一个spring-context-support没有包含在内。
akeng
akeng
刚搞完这个就出现这文章了。。。。
返回顶部
顶部