Quartz
Spring 创建 Quartz 的 Schedule、Trigger 和 JobDetail 提供便利的 FactoryBean类,就能够使用 Spring 注入方式。概括起来提供两方面支持 :
1> 为 Quartz 的重要组件类提供更具 Bean 风格的扩展类
2> 提供创建 Schedule 的 BeanFactory类,方便在 Spring 环境下创建对应的组建对象,并组合 Spring 容器生命周期进行启动和停止动作
使用步骤
1> 在 web.xml 中引入对应的配置文件
<
context-param
>
<
param-name
>
contextConfigLocation
</
param-name
>
<
param-value
>
classpath:applicationContext.xml
</
param-value
>
</
context-param
>
2> 在 applicationContext.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-3.2.xsd
"
default-lazy-init
="true"
>
<!-- Job 任务详情 -->
<
bean
id
="testJob"
class
="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"
>
<
property
name
="targetObject"
ref
="testQuartzService"
/>
<!-- 目标任务 -->
<
property
name
="targetMethod"
value
="test1"
/>
<
property
name
="concurrent"
value
="false"
/>
</
bean
>
<!-- Trigger 调度触发器 -->
<
bean
id
="testTrigger"
class
="org.springframework.scheduling.quartz.CronTriggerFactoryBean"
>
<
property
name
="jobDetail"
ref
="testJob"
/>
<
property
name
="cronExpression"
value
="0/5 * * * * ?"
/>
</
bean
>
<!-- Scheduler 调度工厂 -->
<
bean
id
="testScheduler"
class
="org.springframework.scheduling.quartz.SchedulerFactoryBean"
>
<
property
name
="triggers"
>
<
list
>
<
ref
bean
="testTrigger"
/>
</
list
>
</
property
>
</
bean
>
</
beans
>
也可以单独将配置放入一个文件中
<!--quartz-->
<
import
resource
="classpath:quartz/applicationContext-quartz.xml"
/>
3> 对应的接口实现方法
public interface
TestQuartz {
void
test1();
}
@Service
(
"testQuartzService"
)
@Transactional
public class
TestQuartzImpl
implements
TestQuartz {
Logger
logger
= LoggerFactory.
getLogger
(
this
.getClass());
public void
test1() {
SimpleDateFormat sdf =
new
SimpleDateFormat(
"yyyy-MM-dd HH:mm:ss"
);
this
.
logger
.debug(
this
.getClass().getName() +
">>>>>>>>>>>>>>>>>><<<<<<<<<<<<<<<<< "
+ sdf.format(
new
Date()));
}
}
Quatz 实现集群的方式
方式一 : 通过一个中间数据库,将集群节点相互感知,以实现故障切换
方式二 : 通过 Terracotta 进行集群,Terracotta 是一个 JVM 级的开源集群框架,简单的说就是将多个 JVM 透明化成一个 JVM 使用
Timer 和 TimerTask
TimerTask 代表一个需要多次执行的任务,它实现 Runnable 接口,可以在 run() 方法中定义任务逻辑
TimerTask 相当于 Quartz 中 Job,代表一次任务调度,区别在于 : 每当执行任务时,Quartz 都会创建一个 Job 实例,而 JDK Timer 则使用相同的 TimerTask 实例
Spring 在 org.springframework.schedulingtimer 中提供几个 JDK Timer 的主支持类,主要在以下三个方面对 JDK Timer 提供支持 :
1> ScheduledTimerTask,它对 TimerTask 提供封装并提供相关的配置
2> 通过 MethodInvokingTimerTaskFactoryBean 类可以将一个 Bean 的方法封装封装为 TimerTask
3> 通过 TimerFactoryBean 可以更方便地配置 Timer,此外让 Timer 的生命周期和 Spring容器的生命周期相关,在初始化 TimerFactoryBean 后,启动 Timer,在 Spring 容器关闭前取消 Timer
引入配置文件的方式同上
<
import
resource
="classpath:applicationContext-timer.xml"
/>
applicationContext-timer.xml 中的配置内容
<?
xml version
="1.0"
encoding
="UTF-8"
?>
xmlns:
xsi
="
http://www.w3.org/2001/XMLSchema-instance
"
xmlns:
p
="
http://www.springframework.org/schema/p
"
xsi
:schemaLocation
="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
"
>
<
bean
id
="myService"
class
="com.chenshun.test.timer.MyService"
/>
<
bean
id
="timerTask1"
class
="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
p
:targetObject-ref
="myService"
p
:targetMethod
="doJob"
/>
<!-- 创建定时任务 -->
<
bean
id
="scheduledTask"
class
="org.springframework.scheduling.timer.ScheduledTimerTask"
p
:delay
="10000"
p
:period
="10000"
p
:timerTask-ref
="timerTask1"
/>
<!-- 要运行的定时任务 -->
<
bean
id
="timer"
class
="org.springframework.scheduling.timer.TimerFactoryBean"
>
<
property
name
="scheduledTimerTasks"
>
<
list
>
<
ref
bean
="scheduledTask"
/>
</
list
>
</
property
>
</
bean
>
</
beans
>
对应的执行方法
public class
MyService {
public void
doJob(){
System.
out
.println(
"in MyService.dojob()."
);
}
}
注 : org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean、org.springframework.scheduling.timer.ScheduledTimerTask、org.springframework.scheduling.timer.TimerFactoryBean 这三个类目前都已经被丢弃,在实际开发时使用 Quartz 方式更合适
创建动态任务的方式 :
1> 业务流程产生型 : 在进行一个业务时,在业务操作过程中产生业务
2> 扫面线程产生型 : 由一个任务线程定时扫描业务数据库的任务表,并根据业务数据产生任务
Web 应用程序中调度器的启动和关闭问题
静态变量是ClassLoader 级别,如果 Web应用程序停止,这些静态变量也会从 JVM 中清除。但是线程则是JVM级别的,如果用户在 Web 应用中启动一个线程,这个线程的生命周期并不会和 Web 应用程序保持同步。也就是说,及时停止 Web 应用,这个应用依旧是活跃的。若手动使用 JDK Timer 或 Quartz 的 Scheduler,在 Web 容器启动后再关闭,这个Timer 或 Scheduler还在继续运行
使用Spring 提供 TimerFactoryBean 和 SchedulerFactoryBean 能够和 Spring 容器一起关联,在 Spring 容器停止时,相关调度器停止