环境:springboot2.2.11.RELEASE
2种方式执行定时任务
1、通过springboot的方式
2、使用Quartz实现定时任务
方式一:通过springboot的定时任务
1、开启定时任务功能@EnableScheduling
@SpringBootApplication
@EnableScheduling
public class SpringBootQuartzSchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootQuartzSchedulerApplication.class, args);
}
}
2、编写定时执行的任务@Scheduled
@Component
public class JobExecutor {
// 每3秒执行
@Scheduled(fixedDelay = 3000)
public void process() {
System.out.println("执行任务") ;
}
}
@Scheduled注解的属性说明:
fixedDelay:在上一次调用结束和下一次调用开始之间以毫秒为单位的固定时间段执行。
fixedRate:在调用之间以毫秒为单位执行任务。
initialDelay:延迟指定的毫秒数。
cron:cron表达式。
在这里@Scheduled(cron = "0/2 * * * * ?") 这里的表达式还可以通过配置的方式进行:
@Scheduled(cron = "${custom.cron}")
server:
port: 8080
---
custom:
cron: 0/3 * * * * ?
Cron表达式说明:
cron一定有七位数,最后一位是年,SpringBoot定时方案只需要设置六位即可:
- 第一位, 表示秒, 取值是0 ~ 59
- 第二位, 表示分. 取值是0 ~ 59
- 第三位, 表示小时, 取值是0 ~ 23
- 第四位, 表示天/日, 取值是0 ~ 31
- 第五位, 表示月份, 取值是1 ~ 12
- 第六位, 表示星期, 取值是1 ~ 7, 星期一,星期二..., 还有 1 表示星期日
- 第七位, 年份, 可以留空, 取值是1970 ~ 2099
cron中,还有一些特殊的符号,含义如下:
- (*) 星号,可以理解为每的意思,每秒、每分、每天、每月、每年...。
- (?)问号,问号只能出现在日期和星期这两个位置,表示这个位置的值不确定,每天 3 点执行,因此第六位星期的位置,是不需要关注的,就是不确定的值;同时,日期和星期是两个相互排斥的元素,通过问号来表明不指定值,比如 1 月 10 日是星期一,如果在星期的位置另指定星期二,就前后冲突矛盾了。
- (-)减号,表达一个范围,如在小时字段中使用“10 - 12”,则表示从 10 到 12 点,即 10、11、12。
- (,)逗号,表达一个列表值,如在星期字段中使用“1,2,4”,则表示星期一、星期二、星期四。
- (/)斜杠,如 x/y,x 是开始值,y 是步长,比如在第一位(秒),0/15 就是从 0 秒开始,每隔 15 秒执行一次,最后就是 0、15、30、45、60,另 */y,等同于 0/y。
举几个例子熟悉一下:
- 0 0 3 * * ? :每天 3 点执行;
- 0 5 3 * * ?:每天 3 点 5 分执行;
- 0 5 3 ? * *:每天 3 点 5 分执行,与上面作用相同;
- 0 5/10 3 * * ?:每天 3 点的 5 分、15 分、25 分、35 分、45 分、55分这几个时间点执行;
- 0 10 3 ? * 1:每周星期天,3 点 10 分执行,注,1 表示星期天;
- 0 10 3 ? * 1#3:每个月的第三个星期,星期天执行,# 号只能出现在星期的位置。
springboot自定的定时任务使用非常简单,通过以上简单的方式执行。
方式二:通过Quartz执行定时任务
先了解Quartz的核心类:
Quartz有四个核心概念:
- Job:是一个接口,只定义一个方法 execute(JobExecutionContext context),在实现接口的 execute 方法中编写所需要定时执行的 Job(任务),JobExecutionContext 类提供了调度应用的一些信息;Job 运行时的信息保存在 JobDataMap 实例中,通过JobDataMap 我们可以为任务传参数。
- JobDetail:Quartz 每次调度 Job 时,都重新创建一个 Job 实例,因此它不接受一个 Job 的实例,相反它接收一个 Job 实现类(JobDetail,描述 Job 的实现类及其他相关的静态信息,如 Job 名字、描述、关联监听器等信息),以便运行时通过 newInstance() 的反射机制实例化 Job。
- trigger:是一个类,描述触发 Job 执行的时间触发规则,主要有 SimpleTrigger 和 CronTrigger 这两个子类。当且仅当需调度一次或者以固定时间间隔周期执行调度,SimpleTrigger 是最适合的选择;而 CronTrigger 则可以通过 Cron 表达式定义出各种复杂时间规则的调度方案:如工作日周一到周五的 15:00 ~ 16:00 执行调度等。
- Scheduler:调度器就相当于一个容器,装载着任务和触发器,该类是一个接口,代表一个 Quartz 的独立运行容器,Trigger 和 JobDetail 可以注册到 Scheduler 中,两者在 Scheduler 中拥有各自的组及名称,组及名称是 Scheduler 查找定位容器中某一对象的依据,Trigger 的组及名称必须唯一,JobDetail 的组和名称也必须唯一(但可以和 Trigger 的组和名称相同,因为它们是不同类型的)。Scheduler 定义了多个接口方法,允许外部通过组及名称访问和控制容器中 Trigger 和 JobDetail。
Job 为作业的接口,为任务调度的对象;JobDetail 用来描述 Job 的实现类及其他相关的静态信息;Trigger 作为作业的定时管理工具,一个 Trigger 只能对应一个作业实例,而一个作业实例可对应多个触发器;Scheduler 作为定时任务容器,是 Quartz 最上层的东西,它提携了所有触发器和作业,使它们协调工作,每个 Scheduler 都存有 JobDetail 和 Trigger 的注册,一个 Scheduler 中可以注册多个 JobDetail 和多个 Trigger。
1、添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
2、配置任务Job,JobDetail,Trigger
@Configuration
public class QuartzConfig {
@Bean
public JobDetail sampleJobDetail() {
JobDataMap dataMap = new JobDataMap() ;
dataMap.put("k1", "v1") ;
return Jobbuilder.newJob(SampleJob.class).withIdentity("sampleJob")
.usingJobData("key","pack").usingJobData(dataMap).storeDurably().build() ;
}
/**
* 一个简单的触发器:每隔两秒执行一次(一直重复)
* @return
*/
@Bean
public Trigger sampleJobTrigger(){
SimpleScheduleBuilder scheduleBuilder =
SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(2).repeatForever();
return TriggerBuilder.newTrigger().forJob(sampleJobDetail()).withIdentity("sampleTrigger")
.withSchedule(scheduleBuilder).build();
}
}
任务:
public class SampleJob extends QuartzJobBean {
private static final Logger logger = LoggerFactory.getLogger(SampleJob.class) ;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
logger.info("这里是一个简单的任务") ;
JobDataMap dataMap = context.getJobDetail().getJobDataMap() ;
Set<Entry<String, Object>> entrys = dataMap.entrySet() ;
for (iterator<Entry<String, Object>> iterator = entrys.iterator(); iterator.hasNext();) {
Entry<String, Object> entry = iterator.next();
logger.info("任务数据:key = {}, value = {}", entry.getKey(), entry.getValue()) ;
}
}
}
启动服务:
执行任务也非常简单,接下来通过cron表达式的方式配置触发器:
@Bean
public Trigger cronJobTrigger() {
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule("0/5 * * * * ?") ;
return TriggerBuilder.newTrigger()
.forJob(sampleJobDetail())
.withIdentity("t1", "CRON")
.withSchedule(scheduleBuilder)
.build() ;
}
完毕!!!
给个关注,转发吧,谢谢
Spring MVC 异步请求方式
Spring MVC 异常处理方式
Spring Cloud Sentinel整合Feign
SpringCloud Nacos 整合feign
SpringMVC参数统一验证方法
Springboot Security 基础应用 (1)
SpringBoot中使用Cache及JSR107的使用
SpringBoot RabbitMQ消息可靠发送与接收
Springboot之Actuator详解
Springboot接口幂等性基于token实现方案
,