任务调度
quartz框架
quartz框架实现了Spring的任务调度,用户可以随意的定义触发器调度时间表,并将触发器和任务进行映射。quartz通过调度器、触发器和任务实现任务调度。
Job:主要用来设计任务实现的逻辑,并且只有一个方法execute。
JobDetail:主要用来通过newInstance()方法创建Job实例,该角色主要通过一些静态信息来描述Job的名称等信息。
Triger:作为任务的触发器,有两个类:SimpleTriger和CronTriger。当只触发一次或者周期性触发选择SimpleTriger。当定时触发时可以选择CronTriger。
Calendar:作为时间点的集合。
Scheduler:任务调度容器,Scheduler中注册Triger和JobDetail,将Triger和JobDetail关联起来。
实现任务调度步骤:
1、创建任务,并设置名称和组名。2、创建触发器,并设置名称和组名。3、对触发器设置时间规则。4、定义任务调度容器,将触发器与任务加入容器,并这只关联。
SimpleTriger任务调度实例:
创建任务类
package scheduler;
import org.quartz.Job;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
public class SimpleJob implements Job{
@Override
public void execute(JobExecutionContext arg0) throws JobExecutionException {
// TODO Auto-generated method stub
System.out.println("定时任务调度=================");
}
}
将任务与触发器关联
/**
*
*/
/**
* @author Administrator
*
*/
package scheduler;
import java.util.Collection;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import sun.java2d.pipe.SpanShapeRenderer.Simple;
public class SimpleTriggerRunner {
public static void main(String[] args){
try{
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class).withIdentity("job_1", "group_1").build();
SimpleTrigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("trigger_1","group_triger")
.startNow()
.withSchedule(SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
SchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}catch(Exception e){
e.printStackTrace();
}
}
}
CronTriger实现任务调度实例:
import java.util.Collection;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.TriggerBuilder;
import org.quartz.impl.StdSchedulerFactory;
import sun.java2d.pipe.SpanShapeRenderer.Simple;
public class SimpleTriggerRunner {
public static void main(String[] args){
try{
JobDetail jobDetail = JobBuilder.newJob(SimpleJob.class).withIdentity("job_1", "group_1").build();
SimpleTrigger trigger = TriggerBuilder
.newTrigger()
.withIdentity("trigger_1","group_triger")
.startNow()
.withSchedule(SimpleScheduleBuilder
.simpleSchedule()
.withIntervalInSeconds(5)
.repeatForever())
.build();
SchedulerFactory factory = new StdSchedulerFactory();
Scheduler scheduler = factory.getScheduler();
scheduler.scheduleJob(jobDetail, trigger);
scheduler.start();
}catch(Exception e){
e.printStackTrace();
}
}
}
Spring中使用quartz
创建JobDetailBean
步骤:
1、创建JobDetail实例JobDetailBean。对JobDetailBean进行属性设置,jobClass:用来指定任务;beanName:设置任务的名称;JobDataAsMap为任务的JobDataMap提供值;applicationContextJobDataKey:为Job提供applicationContext。2、创建Trigger触发器,主要是通过SimpleTriggerBean、CronTriggerBean和CronTriggerFactoryBean进行创建,需要将任务实例配置其中。3、通过SchedulerFactoryBean类配置Scheduler,将Trigger加入Schedulerde的Trigger列表中。
实例:
定义任务类
package scheduler;
import java.util.Map;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
import bean.User;
@Component("myJob")
public class MyJob{
public void myexecute() {
// TODO Auto-generated method stub
System.out.println("Spring开始任务调度=========");
System.out.println("Spring结束任务调度==========");
}
}
将任务加入触发器,并设置调度时间。将触发器加入调度。
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
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.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd"
>
<context:component-scan base-package="scheduler"/>
<!-- jobDetail -->
<bean id="jobnew" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="myJob"/>
<property name="targetMethod" value="myexecute"/>
<!--false表示等上一个任务执行完后再开启新的任务-->
<property name="concurrent" value="false"/>
</bean>
<!-- Trigger-->
<bean id="oceanStatusCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="jobnew"/>
<property name="cronExpression" value="0 */2 * * * ?"/>
</bean>
<!--Scheduler -->
<bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="oceanStatusCronTrigger"/>
</list>
</property>
</bean>
</beans>
Spring中使用Timer
Timer
当使用调度比较频繁时,可以考虑使用Timer,并不适合固定时间点例如每周周一上午八点的调度策略。但是对于长时间执行的任务来说,该调度会严重影响性能,因为每一个Timer是在同一个线程,Timer中的有多个TimerTask,执行时间过长容易引起积压。
TmierTask
TimerTask相当于Job,TimerTask实现了Runnable接口,该类中主要有三个方法:任务执行逻辑,执行时间,取消执行。
实现任务调度的步骤:
1、创建TimerTask类。2、创建Timer类。3、将TimerTask实例注册到Timer中。
实例
创建任务实例
package scheduler;
import java.util.TimerTask;
public class SimpleTimerTask extends TimerTask{
private int count=0;
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("线程执行次数========="+count);
count++;
if(count>10){
cancel();
}
}
}
将任务注册到Timer中
package scheduler;
import java.util.Timer;
import java.util.TimerTask;
public class TimerRunner {
public static void main(String[] args){
Timer timer = new Timer();
TimerTask timerTask = new SimpleTimerTask();
timer.schedule(timerTask, 1000, 2000);
}
}
Spring对Timer的使用
创建任务类
package scheduler;
import org.springframework.stereotype.Component;
@Component("myService")
public class MyService {
public void timerTest(){
System.out.println("开始使用TimerTask=========");
}
}
将任务类封装为TimerTask,并将TimerTask设置定时规则,将规则注入Timer。
<!-- 通过生成任务TimerTask -->
<bean id="timerTask" class="org.springframework.scheduling.timer.MethodInvokingTimerTaskFactoryBean"
p:targetObject-ref="myService"
p:targetMethod="timerTest"/>
<!-- 定义调度规则 -->
<bean id="scheduledTask" class="org.springframework.scheduling.timer.ScheduledTimerTask"
p:timerTask-ref="timerTask"
p:delay="1000"
p:period="1000"/>
<!-- 将调度规则放入调度队列 -->
<bean id="timerFactoryBean" class="org.springframework.scheduling.timer.TimerFactoryBean">
<property name="scheduledTimerTasks">
<list>
<ref bean="scheduledTask"/>
</list>
</property>
</bean>
Spring中使用Executor
Executor主要有两个任务:任务提交和任务执行。Executor只有一个方法:void execute(Runnable command),该方法接收任何实现了Runnable的实例。
Executor的简单实现:
package scheduler;
import java.util.concurrent.Executor;
public class SimpleExecutor implements Executor{
@Override
public void execute(Runnable command) {
// TODO Auto-generated method stub
command.run();
}
}
可以为每个任务创建一个线程:
package scheduler;
import java.util.concurrent.Executor;
public class TaskExecutor implements Executor{
@Override
public void execute(Runnable command) {
// TODO Auto-generated method stub
//为每一个任务重新创建一个线程
new Thread(command).start();
}
}
可以将任务放到线程池调度中,每一个任务会通过获取线程,进行任务处理。SchedulerThreadPoolExecutor继承ThreadPoolExecutor,ThreadPoolExecutor继承了Executor和ExecutorService。而SchedulerThreadPoolExecutor通过newFixedThreadPool(int nThreads)创建一个线程池进行任务处理。
使用实例:
package scheduler;
public class SimpleRunnable implements Runnable{
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("开启任务执行==========");
}
}
package scheduler;
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 executeTask(){
for(int i=0;i<6;i++){
executor.execute(new SimpleRunnable());
}
}
public static void main(String args){
ExecutorExample ee = new ExecutorExample();
ee.setExecutor(Executors.newFixedThreadPool(3));
ee.executeTask();
}
}
Spring任务调度的注解支持
@Schedule的实例
配置定时任务:
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:task="http://www.springframework.org/schema/task"
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
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/task
http://www.springframework.org/schema/task/spring-task-4.0.xsd">
<context:component-scan base-package="scheduler"/>
<!-- 启用注解驱动的定时任务 -->
<task:annotation-driven scheduler="myScheduler"/>
<!-- 推荐配置线程池,若不配置多任务下会有问题。后面会详细说明单线程的问题。 -->
<task:scheduler id="myScheduler" pool-size="5"/>
</beans>
创建任务类
package scheduler;
import java.util.Map;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.stereotype.Component;
import bean.User;
@Component("myJob")
public class MyJob{
public void myexecute() {
// TODO Auto-generated method stub
System.out.println("Spring开始任务调度=========");
System.out.println("Spring结束任务调度==========");
}
}