查看官方文档:http://spring.io/guides/gs/scheduling-tasks/ 我们这里将根据官方文档进行讲解如何使用。
使用spirngboot自带的任务调度拢共需要2步
1 启动类上声明 @EnableScheduling
2 spring bean 方法上声明 @Scheduled 并在注解中指定启动的规则
直接上代码
package cn.lijunkui;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication
@EnableScheduling
public class SpringbootlearnApplication {
public static void main(String[] args) {
SpringApplication.run(SpringbootlearnApplication.class, args);
}
}
package cn.lijunkui.task.own;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
*
* @author lijunkui
*
*/
@Component
public class SchedulerTask {
private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
//固定的时间执行 也就是 5秒执行一次
@Scheduled(fixedRate = 5000)
public void reportCurrentTimeFixedRate() {
try {
Thread.sleep(6*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("reportCurrentTimeFixedRate The time is now {}", dateFormat.format(new Date()));
}
}
测试效果
fixedRate:任务执行的时间是3秒 设置任务时间间隔5秒 实际按每5秒执行一次
fixedRate: 任务执行的时间是6秒 设置任务时间间隔5秒 实际按每6秒执行一次
接下俩我们重点说一下 Scheduled 注解 的经常使用参数设置项
fixedRate :固定的时间执行 也就是 多少秒执行一次。 这个我们上面的代码已经介绍完毕。
fixedDelay:执行完毕后再过5秒后执行
initialDelay:启动后延迟多少秒后执行 不能单独使用。
接下俩看看fixedDelay 和 initialDelay 设置项的demo案例:
package cn.lijunkui;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import cn.lijunkui.task.own.SchedulerTask;
@SpringBootApplication
@EnableScheduling
public class SpringbootlearnApplication {
private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
public static void main(String[] args) {
SpringApplication.run(SpringbootlearnApplication.class, args);
log.info("reportCurrentTimeInitialDelay fixedRate The time is start {}", dateFormat.format(new Date()));
}
}
package cn.lijunkui.task.own;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
*
* @author jrrry
*
*/
@Component
public class SchedulerTask {
private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Scheduled(initialDelay=0, fixedDelay=5000)
public void reportCurrentTimeInitialDelay() {
try {
Thread.sleep(6*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("reportCurrentTimeInitialDelay fixedRate The time is now {}", dateFormat.format(new Date()));
}
}
测试结果:
fixedDelay:任务执行的时间是3秒 设置任务时间间隔5秒 实际按每8秒执行一次
fixedDelay:任务执行的时间是6秒 设置任务时间间隔5秒 实际按每11秒执行一次
同时 Scheduled 还支持 Cron 表达式方式
package cn.lijunkui.task.own;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class SchedulerTaskForCron {
private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
/**
* 每天的14:00 执行一次
*/
@Scheduled(cron="0 0 14 * * ?")
private void cron() {
log.info("cron The time is now {}", dateFormat.format(new Date()));
}
/**
* 每5秒执行一次
*/
@Scheduled(cron="0/5 * * * * ?")
private void cron2() {
try {
Thread.sleep(6*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("cron2 The time is now {}", dateFormat.format(new Date()));
}
}
测试结果:
任务执行的时间是3秒 设置任务时间间隔5秒 实际按每5秒执行一次
任务执行的时间是6秒 设置任务时间间隔5秒 实际按每11秒执行一次
关于cron使用规则 网上有很多在线生成工具 例如:http://www.bejson.com/othertools/cron/
package cn.lijunkui.task.jdk;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimerTask;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.lijunkui.task.own.SchedulerTask;
public class DemoTask extends TimerTask{
private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Override
public void run() {
try {
Thread.sleep(4*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("DemoTask The time is now {}", dateFormat.format(new Date()));
}
}
package cn.lijunkui.task.jdk;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Timer;
public class TimerTest {
private DemoTask demoTask;
public TimerTest(DemoTask demoTask) {
this.demoTask = demoTask;
}
public void run() throws ParseException {
Timer timer = new Timer();
long delay = 0;
long intevalPeriod = 1 * 1000;
//timer.scheduleAtFixedRate(demoTask, delay, intevalPeriod);//每秒执行一次
//timer.scheduleAtFixedRate(demoTask, 1000, intevalPeriod);//延迟一秒后每秒执行一次
String datetimeStr = "2018-10-16 15:00:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date firstTime = sdf.parse(datetimeStr);
timer.schedule(demoTask, firstTime, intevalPeriod);//3点后开始执行 每秒执行一次
}
}
package cn.lijunkui.task.jdk;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
@Component
@Order(value = 1)
public class DemoTaskRunner implements ApplicationRunner{
@Override
public void run(ApplicationArguments args) throws Exception {
TimerTest test = new TimerTest(new DemoTask());
test.run();
}
}
schedule: 任务执行时间是2秒 设置的时间间隔是3秒 我们的任务是每3秒执行一次
schedule: 任务执行时间是4秒 设置的时间间隔是3秒 我们的任务是每4秒执行一次
scheduleAtFixedRate:任务执行时间是2秒 设置的时间间隔是3秒 我们的任务是每3秒执行一次
scheduleAtFixedRate:任务执行时间是4秒 设置的时间间隔是3秒 我们的任务是每4秒执行一次
Java SE5 java.util.concurrent里 ScheduledExecutorService 提供了新的任务调度的方式。他是采用线程池的方式来执行的,相对于 Timer 语法更为简单。
package cn.lijunkui.task.jdk.scheduledExecutorService;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.lijunkui.task.own.SchedulerTask;
public class ScheduledExecutorTask implements Runnable{
private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Override
public void run() {
try {
Thread.sleep(4*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("scheduledExecutorTask The time is now {}", dateFormat.format(new Date()));
}
}
package cn.lijunkui.task.jdk.scheduledExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class ScheduledExecutorTest {
private ScheduledExecutorTask task;
public ScheduledExecutorTest(ScheduledExecutorTask task) {
this.task = task;
}
public void run() {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
//当任务时间小于设置时间间隔则以设置的时间间隔为准
//当任务执行时间大于设置的间隔时间时,真正间隔的时间由任务执行时间为准!
//service.scheduleAtFixedRate(task, 0, 3, TimeUnit.SECONDS);//不延迟执行
//时间间隔是设置的间隔时间+执行任务的时间
//service.scheduleWithFixedDelay(task,0, 3, TimeUnit.SECONDS);//不延迟执行
//只执行一次时间间隔是设置的间隔时间+执行任务的时间
service.schedule(task, 3, TimeUnit.SECONDS);
}
}
package cn.lijunkui.task.jdk.timer;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import cn.lijunkui.task.jdk.scheduledExecutorService.ScheduledExecutorTask;
import cn.lijunkui.task.jdk.scheduledExecutorService.ScheduledExecutorTest;
@Component
@Order(value = 1)
public class DemoTaskRunner implements ApplicationRunner{
@Override
public void run(ApplicationArguments args) throws Exception {
//TimerTest test = new TimerTest(new DemoTask());
//test.run();
ScheduledExecutorTest test = new ScheduledExecutorTest(new ScheduledExecutorTask());
test.run();
}
}
测试结果:
scheduleAtFixedRate: 任务执行时间是2秒 设置的时间间隔是3秒 我们的任务是每3秒执行一次
scheduleAtFixedRate: 任务执行时间是4秒 设置的时间间隔是3秒 我们的任务是每4秒执行一次
scheduleWithFixedDelay : 任务执行时间是2秒 设置的时间间隔是3秒 我们的任务是每5秒执行一次
scheduleWithFixedDelay : 任务执行时间是4秒 设置的时间间隔是3秒 我们的任务是每7秒执行一次
schedule: 任务执行时间是2秒 设置的时间间隔是3秒 我们的任务是每5秒执行一次
schedule: 任务执行时间是4秒 设置的时间间隔是3秒 我们的任务是每7秒执行一次
通过上面测试scheduleAtFixedRate 和 scheduleWithFixedDelay 我们建议使用scheduleAtFixedRate 因为他的时间间隔更为合理。
springboot 2.0 已经有了quartz 的start依赖,我们可以直接引入quartz 的start依赖 来使用quartz 了。
首先我们先引入quartz start依赖
org.springframework.boot
spring-boot-starter-quartz
定义quartz 的job
package cn.lijunkui.task.quartz.simple;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import cn.lijunkui.task.own.SchedulerTask;
import cn.lijunkui.task.quartz.simple.service.OrderService;
public class SimpleJob extends QuartzJobBean{
private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Autowired
private OrderService orderService;//订单service
private String serviceCode;//业务code
public String getServiceCode() {
return serviceCode;
}
public void setServiceCode(String serviceCode) {
this.serviceCode = serviceCode;
}
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
System.out.println(serviceCode);
log.info("quartz simple The time is now {}", dateFormat.format(new Date()));
orderService.delete();
}
}
创建quartz 的Config 同时定义 JobDetail 和 触发器 Trigger
package cn.lijunkui.task.quartz.simple;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class SimpleJobConfig {
@Bean
public JobDetail simpleJobDetail() {
return JobBuilder.newJob(SimpleJob.class).withIdentity("myJob").storeDurably()
.usingJobData("serviceCode","delete overdue orders")
.build();
}
@Bean
public Trigger simpleJobTrigger() {
//定义每三秒执行一次
SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(3).repeatForever();
//定义触发器
return TriggerBuilder.newTrigger().forJob(simpleJobDetail()).withIdentity("myJobTrigger").withSchedule(simpleScheduleBuilder).build();
}
}
定义注入的Job的Service
package cn.lijunkui.task.quartz.simple.service;
import org.springframework.stereotype.Service;
@Service
public class OrderService {
public void delete() {
try {
Thread.sleep(6*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("delete data sucess....");
}
}
测试日志:
orderService延时 2秒 任务是按照每3秒执行一次
orderService延时 6秒 任务是按照每3秒执行一次
quartz 使用cron 表达式
cron 表达式操作方式和上面的基本一致 不过我们的job需要实现Job而不是使用继承的方式,我们这里定义2内容一致的job 具体代码如下:
package cn.lijunkui.task.quartz.cron;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import cn.lijunkui.task.own.SchedulerTask;
import cn.lijunkui.task.quartz.cron.service.LiveReminderService;
public class CronJob implements Job{
private static final Logger log = LoggerFactory.getLogger(SchedulerTask.class);
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");
@Autowired
private LiveReminderService liveReminderService;//直播课提醒
private String serviceCode;//业务code Live lesson reminder
public String getServiceCode() {
return serviceCode;
}
public void setServiceCode(String serviceCode) {
this.serviceCode = serviceCode;
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
log.info("quartz cron The time is now {}", dateFormat.format(new Date()));
System.out.println("CronJob"+serviceCode);
liveReminderService.sendmessage();
}
}
package cn.lijunkui.task.quartz.cron;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import cn.lijunkui.task.quartz.cron.service.LiveReminderService;
public class CronJob2 implements Job{
@Autowired
private LiveReminderService liveReminderService;//直播课提醒
private String serviceCode;//业务code Live lesson reminder
public String getServiceCode() {
return serviceCode;
}
public void setServiceCode(String serviceCode) {
this.serviceCode = serviceCode;
}
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("CronJob2"+serviceCode);
liveReminderService.sendmessage();
}
}
定义cron 表达式 集成JobDetail 和 触发器 Trigger的manger类和上面定义的Config原理一样。
package cn.lijunkui.task.quartz.cron;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.JobBuilder;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.TriggerBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import org.springframework.stereotype.Component;
@Component
public class CronSchedulerJobManger {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
public void scheduleJobs() throws SchedulerException {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduleJob1(scheduler);
//scheduleJob2(scheduler);
}
private void scheduleJob1(Scheduler scheduler) throws SchedulerException{
JobDetail jobDetail = JobBuilder.newJob(CronJob.class) .withIdentity("job1", "group1")
.usingJobData("serviceCode","Live lesson reminder1").build();
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?");
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "group1") .withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
private void scheduleJob2(Scheduler scheduler) throws SchedulerException{
JobDetail jobDetail = JobBuilder.newJob(CronJob2.class) .withIdentity("job2", "group2")
.usingJobData("serviceCode","Live lesson reminder2").build();
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/10 * * * * ?");
CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity("trigger2", "group2") .withSchedule(scheduleBuilder).build();
scheduler.scheduleJob(jobDetail,cronTrigger);
}
}
定义直播课提醒的service
package cn.lijunkui.task.quartz.cron.service;
import org.springframework.stereotype.Service;
@Service
public class LiveReminderService {
public void sendmessage() {
try {
Thread.sleep(10*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("xiaoming xiaoliu xiaoli has 3:00 Live broadcast lesson");
}
}
定义启动类 使项目一启动就执行 CronSchedulerJobManger 的定时任务。
package cn.lijunkui.task.quartz.cron;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;
@Component
public class CronSchedulerRunner implements CommandLineRunner {
@Autowired
public CronSchedulerJobManger manger;
@Override
public void run(String... args) throws Exception {
manger.scheduleJobs();
}
}
测试结果:
任务执行时间4秒 定时任务设置时间间隔 5秒 实际执行效果是每5秒执行一次
任务执行时间10秒 定时任务设置时间间隔 5秒 实际执行效果是每5秒执行一次
开发工具:Spring Tool Suite (STS)
jdk版本:1.8.0_144
springboot版本:2.0.5.RELEASE
查看源码