定时任务实现概述
定时任务是企业级开发中最常见的功能之一,如定时统计订单数、定时同步数据、定时发送短信和邮件。简单执行的定时任务可以通过@Scheduled实现,复杂的定时任务可以通过Quartz来实现。
Scheduled
@Scheduled是由Spring提供的定时任务注解,使用方便,配置简单。在使用定时任务执行某项操作(发送邮件、同步数据),不考虑定时任务调度持久化时使用。
Quartz
Quartz是一个功能丰富的开源作业调度库,使用Java编写,可以在Java应用程序中集成使用。使用Quartz可以创建简单或复杂的执行计划,支持持久化、集群、cron表达式等,具有极高的灵活性。
在与SpringBoot2.x整合的过程中,主要提供三个Bean:JobDetail、Trigger、SchedulerFactory。
JobDetail:用来保存Job的详细信息(Job名称、Job描述、关联监听器等)。一个JobDetail可以有多个Trigger,一个Trigger对应一个JobDetail。
Trigger:描述触发定时任务的执行规则。主要有SimpleTrigger和CronTrigger两个子类。SimpleTrigger适用于触发一次或以固定间隔周期执行;CronTrigger可以通过Cron表达式定义各种复杂规则时间调度方案。
Scheduler:负责管理Quartz运行环境。Trigger和JobDetail都可以注册到Scheduler中。Scheduler可以将Trigger绑定到一个JobDetail中,当Trigger触发时,对应的Job会自动执行。Scheduler拥有一个SchedulerContext,保存着Scheduler上下文信息,JobDetail和Trigger都可以访问Scheduler上下文信息。
定时任务使用示例
Scheduled使用示例
引入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
编写定时任务
package com.springboot.demo.scheduled;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Date;
@Component
public class ScheduledDemo {
@Scheduled(fixedDelay = 1000)
public void fixedDelay()
{
System.out.println("fixedDelay:"+new Date());
}
@Scheduled(fixedRate=2000)
public void fixedRate()
{
System.out.println("fixedRate:"+new Date());
}
@Scheduled(initialDelay = 1000,fixedRate = 2000)
public void initialDelay()
{
System.out.println("initialDelay:"+new Date());
}
@Scheduled(cron = "0 * * * * ?")
public void cron()
{
System.out.println("cron---------"+new Date());
}
}
@Scheduled用于标注一个定时任务,参数定义及作用如下
参数名称 | 参数作用
|
fixedDelay | 定时任务执行完成后开始计时
|
fixedRate
| 定时任务开始执行时开始计时
|
initialDelay | 首次执行定时任务延时时间
|
cron | cron表达式 |
cron表达式详解
cron表达式完整字段如下:[秒][分][小时][日][月][周][年]
字段 | 值区间
| 允许特殊字符
|
秒 | 0-59 | ,-*/
|
分 | 0-59 | ,-*/
|
小时
| 0-23 | ,-*/
|
日 | 1-31
| ,-*?/LWC
|
月
| 1-12或JAN-DEC
| ,-*/
|
周
| 1-7或SUN-SAT
| ,-*?/LC#
|
年
| 留空或1970-2099
| ,-*/ |
特殊字符含义如下
特殊字符 | 含义
|
, | 用于表示多个值间隔,每个值均会执行定时任务
|
- | 用于表示区间,区间内所有值均会执行定时任务
|
* | 表示所有值。设置在秒字段表示每秒执行定时任务
|
?
| 不指定值。不关心当前设置的值,用于日期和周重复现象
|
/
| 表示递增触发。如分字段设置为0/15表示从0分钟开始,每隔15分钟触发定时任务执行
|
L | 表示最后的意思。日上设置表示最后一天,周上设置表示最后一周。前面加数字,如周设置为6L,表示最后一个周五
|
W
| 离指定日期最近的工作日触发
|
#
| 用于设置每个月第几个周几,1#3每个月第三个周日 |
C
| Calendar,计划所关联之后的第一天,日上设置为5C,代表每月5号后的第一天;周字段上设置5C,代表每周每周四后的第一天
|
QUARTZ使用示例
引入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-quartzartifactId>
dependency>
定时任务实例
@Component
public class FirstJob {
public void firstJobTest()
{
System.out.println("firstJob-------"+new Date());
}
}
@Component
public class SecondJob extends QuartzJobBean {
private String message;
public void setMessage(String message) {
this.message = message;
}
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("info------"+message+"--------"+new Date());
}
}
定时任务可以是一个普通的JavaBean,也可以是QuartzJobBean子类。继承自QuartzJobBean需要实现executeInternal方法,该方法用于在定时任务执行时被调用。
定时任务配置
@Configuration
public class QuartzConfig {
/**
* 通过 MethodInvokingJobDetailFactoryBean配置JobDetail
* @return JobBean
*/
@Bean
MethodInvokingJobDetailFactoryBean getFirstJobDetail()
{
MethodInvokingJobDetailFactoryBean firstJobBean=new MethodInvokingJobDetailFactoryBean();
firstJobBean.setTargetBeanName("firstJob");
firstJobBean.setTargetMethod("firstJobTest");
return firstJobBean;
}
@Bean
JobDetailFactoryBean getSecondJobDetail()
{
JobDetailFactoryBean secOndJob=new JobDetailFactoryBean();
secondJob.setJobClass(SecondJob.class);
//设置参数
JobDataMap dataMap=new JobDataMap();
dataMap.put("message","quartzJobInfo");
secondJob.setJobDataMap(dataMap);
secondJob.setDurability(true);
return secondJob;
}
/**
* 简易触发器
* @return 简易触发器实例
*/
@Bean
SimpleTriggerFactoryBean getSimpleTrigger()
{
//初始化简易触发器
SimpleTriggerFactoryBean simpleTriggerBean=new SimpleTriggerFactoryBean();
//为触发器绑定定时任务
simpleTriggerBean.setJobDetail(getFirstJobDetail().getObject());
//设置定时任务执行次数
simpleTriggerBean.setRepeatCount(3);
//定时任务初始化执行延迟时间
simpleTriggerBean.setStartDelay(1000);
//定时任务执行时间间隔
simpleTriggerBean.setRepeatInterval(2000);
return simpleTriggerBean;
}
/**
* Crom表达式触发器
* @return cron表达式触发器实例
*/
@Bean
CronTriggerFactoryBean getCronTrigger()
{
//初始化Cron表达式触发器
CronTriggerFactoryBean crOnTrigger=new CronTriggerFactoryBean();
//触发器绑定定时任务
cronTrigger.setJobDetail(getSecondJobDetail().getObject());
//设置cron表达式
cronTrigger.setCronExpression("0 * * * * ? ");
return cronTrigger;
}
/**
* 创建定时任务工厂并设置触发器
* @return 定时任务工厂
*/
@Bean
SchedulerFactoryBean getSchedulerFactory()
{
//初始化定时任务工厂实例
SchedulerFactoryBean schedulerFactory=new SchedulerFactoryBean();
//获取绑定定时任务后的触发器
SimpleTrigger simpleTrigger=getSimpleTrigger().getObject();
CronTrigger crOnTrigger=getCronTrigger().getObject();
//为定时任务工厂设置触发器
schedulerFactory.setTriggers(simpleTrigger,cronTrigger);
//返回定时任务工厂
return schedulerFactory;
}
}
JobDetail的实例化有两种方式
通过MethodInvokingJobDetailFactoryBean实例化JobDetail,分别设置需要执行的JobDetail实例名(setTargetBeanName)和实例方法(setTargerMethod)就可以实例化JobDetail,无法为该JobDetail实例设置参数
通过JobDetailFactoryBean实例化JobDetail。需要指定JobDetail类名(setJobClass(Class)),并通过JobDataMap实例为该JobDetail设置参数(dataMap.put(propertyName,value);)
Quartz包含了多种触发器,这里只展示简易触发器(SimpleTrigger)和Cron表达式触发器(CronTrigger)。
简易触发器(SimpleTrigger)。在简易触发器中,首先需要为触发器绑定定时任务实例(simpleTriggerBean.setJobDetail()),然后设置定时任务执行次数( simpleTriggerBean.setRepeatCount())、定时任务首次执行延迟时间(simpleTriggerBean.setStartDelay())、定时任务执行间隔时间(simpleTriggerBean.setRepeatInterval())。
Cron表达式触发器(CronTrigger)。在Cron表达式触发器中,首先需要为触发器绑定定时任务实例(cronTrigger.setJobDetail()),然后设置cron表达式(cronTrigger.setCronExpression(""))。
最后通过SchedulerFactoryBean创建实例,并设置对应的触发器即可。
主程序入口
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}