Spring为创建Quartz中的Scheduler、JobDetail和Tirgger提供了便利的factoryBean,以便在Spring容器中享受注入的好处,此外,Spring还提供了一些便利的工具直接将Spring中的Bean包装为合法的任务。
1.创建JobDetail
1)通过JobDetailBean
<bean id="jobDetail" class="org.springframework.scheduling.quartz.JobDetailBean" p:jobClass="com.test.quartz.MyJob" p:applicationContextJobDataKey="applicationContext"> <property name="jobDataAsMap"> <map> <entry key="size" value="10"/> </map> </property> </bean>
package com.test.quartz; import java.util.Map; import org.apache.catalina.core.ApplicationContext; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; public class MyJob implements Job{ @Override public void execute(JobExecutionContext jctx) throws JobExecutionException { Map dataMap=jctx.getJobDetail().getJobDataMap(); String size=(String) dataMap.get("size"); ApplicationContext applicationContext=(ApplicationContext) dataMap.get("applicationContext"); System.out.println("size:"+size); dataMap.put("size", size+"0");//更改是否可见,取决于任务的类型,如果实现StatefulJob,那么这次更改对于下次执行就是可见的 //do sth } }
2)MethodInvokingJobDetailFactoryBean
可以将Spring Bean包装为任务
<bean id="jobDetail_1" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean" p:targetObject-ref="myService" p:targetMethod="doJob" p:concurrent="false"><!-- 指定任务是否有状态,false为有状态的任务,有状态的任务不能并发执行 --> </bean> <bean id="myService" class="com.test.quartz.MyService"/>
package com.test.quartz; public class MyService { public void doJob(){ System.out.println("in myService.doJob()"); //doJob可以是static,也可以是非static,但是不能有参数,通过MethodInvokingJobDetailFactoryBean创建的JobDetail不能被持久化到数据库,想要持久化,要用正规的Quartz Job实现类 } }
2创建Trigger
1)SimpleTriggerBean
属性:JobDetail beanName jobDataAsMap startDelay延时多少时间开始触发 triggerListenerNames
<bean id="simpleTrigger1" class="org.springframework.scheduling.quartz.SimpleTriggerBean" p:jobDetail-ref="jobDetail" p:startDelay="1000" p:repeatInterval="2000" p:repeatCount="100"> <property name="jobDataAsMap"> <map> <entry key="count" value="10"/> </map> </property> </bean>
package com.test.quartz; import java.util.Map; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.StatefulJob; public class MyJob implements StatefulJob{ @Override public void execute(JobExecutionContext jctx) throws JobExecutionException { Map dataMap=jctx.getTrigger().getJobDataMap(); String count=(String) dataMap.get("count"); dataMap.put("count", "30"); //do sth } }
2)CronTriggerBean
<bean id="cronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean" p:jobDetail-ref="jobDetail" p:cronExpression="0/5 * * * * ?"/>
3 创建 Scheduler
Spring提供了SchedulerFactoryBean,可以以Bean风格方式配置Scheduler,并且让Scheuler和Spring容器生命周期建立关联,相生相息。通过属性配置方式代替quartz自身配置文件
<bean id="scheduler" class="org.springframework.scheduling.quartz.SchedulerFactoryBean"> <property name="triggers"> <list> <ref bean="simpleTrigger1"/> </list> </property> <property name="schedulerContextAsMap"> <map> <entry key="timeout" value="30"/> </map> </property> <property name="configLocation" value="classpath:com/test/quartz/quartz.properties" /> </bean>
ScheduleFactoryBean的一些其他属性:
calendars 类型为map
jobDetails 类型为jobDetail[]
autoStartup :ScheduleFactoryBean是否在初始化后,马上启动scheduler,默认为true
startupDelay:ScheduleFactoryBean初始化后,延迟多少秒启动Scheduler,默认为0,马上启动。
ScheduleFactoryBean通过以下属性,代替框架自身的配置文件。
dataSource 可以覆盖quartz.proeprties定义的数据源
transactionManager 设置一个Spring事务管理器
nonTransactionalDataSource 在全局事务情况下,如何用户不希望Schedule执行的相关数据操作参与到全局事务中,可以通过该属性指定数据源。
quartzProperties,类型为Properties,允许用户在Spring中定义quartz属性,其值会覆盖quartz.properties中设置的属性值。
二、拓展
1.Spring中使用JDK Timer
JDK Timer只适合对执行时间非常短的任务进行调度,允许按照固定频率重复执行某项任务。
TimerTask
相当于quartz中的一个job,代表一个任务,两者主要区别是每当执行一个任务,,quartz都会创建一个job实例,而jDK Timer使用相同的TimerTask实例,如果TimerTask是有状态的,这些状态对后面的执行时可见的,3个方法
abstract void run()
boolean cancel() 取消任务
long scheduledExecutionTime(),返回此任务的计划执行时间点。一般在run()方法中调用,判断是否取消本次任务的执行
Timer
在延迟一段时间或指定时间点后执行一次任务或周期性运行任务 Object#wait()进行任务的时间调度。
Timer()
Timer(boolean isDaemon)
Timer(String name)
Timer(String name,boolean isDaemon)
schedule(TimerTask task,Date time)
schedule(TimerTask task,long delay)
schedule(TimerTask task,Date firstTime,long period)
schedule(TimerTask task,long delay,long period)
scheduleAtFixedRate(TimerTask task,Date firstTime,long period)
scheduleAtFixedRate(TimerTask task,long delay,long period)
cancel()
purge()
Spring对JDK Timer的支持
1)使用ScheduleTimerTask
<bean id="timerTask" class="com.test.timer.SimpleTimerTask"/> <bean id="scheduledTask1" class="org.springframework.scheduling.timer.ScheduledTimerTask" p:timerTask-ref="timerTask" p:delay="1000" p:period="1000" p:fixedRate="false"> </bean>
2)使用MethodInvokingTimerTaskFactoryBean
<bean id="myService" class="com.test.quartz.MyService"/> <bean id="scheduledTask2" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean" p:targetObject-ref="myService" p:targetMethod="doJob"> </bean>
3)TimerFactoryBean
<bean id="timer" class="org.springframework.scheduling.timer.TimerFactoryBean"> <property name="scheduledTimerTasks"> <list> <ref bean="scheduledTask1"/> <ref bean="scheduledTask2"/> </list> </property> </bean>
2 Spring中使用JDK 5.0 Executor
JDK5.0新增了并发工具包,java.util.concurrent,包含了执行器,任务调度框架,线程安全队列,锁,计时器和其他一些同步的基本类型
Executor将任务提交和任务执行解耦。void execute(Runnable runnable)可以通过方法调用提交多个任务 两个子接口 ExecutorService和ScheduledExecutorService,ExecutorService添加了任务结束的方法,可以在提交任务时获取一个Future实例,跟踪任务异步执行情况,ScheduledExecutorService可以进行调度,如ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit);指定任务延时一段时间后执行。
实现:ThreadPoolExecutor类实现了Executor和ExecutorService,ScheduledThreadPoolExecutor实现了ScheduledExecutorService接口,添加了对任务调度的功能。
提供了综合的工厂类Executors
public static ExecutorService newFixedThreadPool(int nThreads)创建一个线程池,复用一组固定的线程运行一个共享的无界队列
public static ExecutorService newCachedThreadPool()线程池是动态的,不够用时创建,空闲时收回
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory)创建一个线程池,可以在延时一段时间后执行或定期执行。
package com.test.executors; import java.util.concurrent.Executor; import java.util.concurrent.Executors; public class ExecutorExample { private Executor executor; public void setExecutor(Executor executor) { this.executor = executor; } public void executorTask(){ for (int i = 0; i < 6; i++) { executor.execute(new SimpleTask("task"+i)); } } class SimpleTask implements Runnable{ private String taskName; public SimpleTask(String taskName){ this.taskName=taskName; } @Override public void run() { System.out.println("do "+taskName +"...in Thread:"+Thread.currentThread().getId()); } } public static void main(String[] args) { ExecutorExample example=new ExecutorExample(); example.setExecutor(Executors.newFixedThreadPool(3)); example.executorTask(); } }
Spring对JDK 5.0 Executor的支持
Spring对Executor所提供的抽象
org.springframework.core.task.TaskExecutor接口等同于Executor接口。
SchedulingTaskExecutor子接口,新增任务调度规则制定的功能‘
Spring提供的一些TaskExecutor的实现
SyncTaskExecutor org.springframework.core.task包中,实现了TaskExecutor接口,这个实现不会异步执行任务,相反每回都在发起调用的主线程中执行。
SimpleSyncTaskExecutor org.springframework.core.task包中,没有使用线程池,每回执行任务时都新创建一个线程,但是对并发总数有限制
ConcurrentTaskExecutor jdk5.0Executor适配器 org.springframework.scheduling.concurrent
SimpleThreadPoolTaskExecutor org.springframework.scheduling.quartz包中,实际上继承Quartz包中SimpleThreadPool类的子类,它监听Spring的生命周期回调
ThreadPoolTaskExecutor.只能在JDK 5.0中使用, org.springframework.scheduling.concurrent ThreadPoolExecutor包装为TaskExecutor
TimerTaskExecutor 该类使用一个Timer作为其后台实现 org.springframework.scheduling.timer
package com.test.executors; import org.springframework.core.task.SimpleAsyncTaskExecutor; import org.springframework.core.task.TaskExecutor; public class ExecutorExample { private TaskExecutor executor; public void setExecutor(TaskExecutor executor) { this.executor = executor; } public void executorTask(){ for (int i = 0; i < 6; i++) { executor.execute(new SimpleTask("task"+i)); } } class SimpleTask implements Runnable{ private String taskName; public SimpleTask(String taskName){ this.taskName=taskName; } @Override public void run() { System.out.println("do "+taskName +"...in Thread:"+Thread.currentThread().getId()); } } public static void main(String[] args) { ExecutorExample example=new ExecutorExample(); example.setExecutor(new SimpleAsyncTaskExecutor()); example.executorTask(); } }