在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Quartz ,Spring Boot 源自 Spring+SpringMVC ,因此天然具备这两个 Spring 中的定时任务实现策略,当然也支持 Quartz,本文我们就来看下 Spring Boot 中两种定时任务的实现方式。

@Scheduled

使用 @Scheduled 非常容易,直接创建一个 Spring Boot 项目,并且添加 web 依赖 spring-boot-starter-web,项目创建成功后,添加 @EnableScheduling 注解,开启定时任务:

@SpringBootApplication
@EnableScheduling
public class ScheduledApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduledApplication.class, args);
}
}

接下来配置定时任务:

    @Scheduled(fixedRate = 2000)
public void fixedRate() {
System.out.println("fixedRate>>>"+new Date());
}
@Scheduled(fixedDelay = 2000)
public void fixedDelay() {
System.out.println("fixedDelay>>>"+new Date());
}
@Scheduled(initialDelay = 2000,fixedDelay = 2000)
public void initialDelay() {
System.out.println("initialDelay>>>"+new Date());
}
  1. 首先使用 @Scheduled 注解开启一个定时任务。
  2. fixedRate 表示任务执行之间的时间间隔,具体是指两次任务的开始时间间隔,即第二次任务开始时,第一次任务可能还没结束。
  3. fixedDelay 表示任务执行之间的时间间隔,具体是指本次任务结束到下次任务开始之间的时间间隔。
  4. initialDelay 表示首次任务启动的延迟时间。
  5. 所有时间的单位都是毫秒。

上面这是一个基本用法,除了这几个基本属性之外,@Scheduled 注解也支持 cron 表达式,使用 cron 表达式,可以非常丰富的描述定时任务的时间。cron 表达式格式如下:

[秒] [分] [小时] [日] [月] [周] [年]

具体取值如下:

序号 说明 是否必填 允许填写的值 允许的通配符
1 0-59 - * /
2 0-59 - * /
3 0-23 - * /
4 1-31 - * ? / L W
5 1-12 or JAN-DEC - * /
6 1-7 or SUN-SAT - * ? / L ##
7 1970-2099 - * /

这一块需要大家注意的是,月份中的日期和星期可能会起冲突,因此在配置时这两个得有一个是 ?

通配符含义:

  • ? 表示不指定值,即不关心某个字段的取值时使用。需要注意的是,月份中的日期和星期可能会起冲突,因此在配置时这两个得有一个是 ?
  • * 表示所有值,例如:在秒的字段上设置 *,表示每一秒都会触发
  • , 用来分开多个值,例如在周字段上设置 "MON,WED,FRI" 表示周一,周三和周五触发
  • - 表示区间,例如在秒上设置 "10-12",表示 10,11,12秒都会触发
  • / 用于递增触发,如在秒上面设置"5/15" 表示从5秒开始,每增15秒触发(5,20,35,50)
  • ## 序号(表示每月的第几个周几),例如在周字段上设置"6##3"表示在每月的第三个周六,(用 在母亲节和父亲节再合适不过了)
  • 周字段的设置,若使用英文字母是不区分大小写的 ,即 MON 与mon相同
  • L 表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会自动判断是否是润年), 在周字段上表示星期六,相当于"7"或"SAT"(注意周日算是第一天)。如果在"L"前加上数字,则表示该数据的最后一个。例如在周字段上设置"6L"这样的格式,则表示"本月最后一个星期五"
  • W 表示离指定日期的最近工作日(周一至周五),例如在日字段上设置"15W",表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发,如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 "1W",它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,"W"前只能设置具体的数字,不允许区间"-")
  • LW 可以一组合使用。如果在日字段上设置"LW",则表示在本月的最后一个工作日触发(一般指发工资 )

例如,在 @Scheduled 注解中来一个简单的 cron 表达式,每隔5秒触发一次,如下:

@Scheduled(cron = "0/5 * * * * *")
public void cron() {
System.out.println(new Date());
}

上面介绍的是使用 @Scheduled 注解的方式来实现定时任务,接下来我们再来看看如何使用 Quartz 实现定时任务。

Quartz

一般在项目中,除非定时任务涉及到的业务实在是太简单,使用 @Scheduled 注解来解决定时任务,否则大部分情况可能都是使用 Quartz 来做定时任务。在 Spring Boot 中使用 Quartz ,只需要在创建项目时,添加 Quartz 依赖即可:

项目创建完成后,也需要添加开启定时任务的注解:

@SpringBootApplication
@EnableScheduling
public class QuartzApplication {
public static void main(String[] args) {
SpringApplication.run(QuartzApplication.class, args);
}
}

Quartz 在使用过程中,有两个关键概念,一个是JobDetail(要做的事情),另一个是触发器(什么时候做),要定义 JobDetail,需要先定义 Job,Job 的定义有两种方式:

第一种方式,直接定义一个Bean:

@Component
public class MyJob1 {
public void sayHello() {
System.out.println("MyJob1>>>"+new Date());
}
}

关于这种定义方式说两点:

  1. 首先将这个 Job 注册到 Spring 容器中。
  2. 这种定义方式有一个缺陷,就是无法传参。

第二种定义方式,则是继承 QuartzJobBean 并实现默认的方法:

public class MyJob2 extends QuartzJobBean {
HelloService helloService;
public HelloService getHelloService() {
return helloService;
}
public void setHelloService(HelloService helloService) {
this.helloService = helloService;
}
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
helloService.sayHello();
}
}
public class HelloService {
public void sayHello() {
System.out.println("hello service >>>"+new Date());
}
}

和第1种方式相比,这种方式支持传参,任务启动时,executeInternal 方法将会被执行。

Job 有了之后,接下来创建类,配置 JobDetail 和 Trigger 触发器,如下:

@Configuration
public class QuartzConfig {
@Bean
MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean() {
MethodInvokingJobDetailFactoryBean bean = new MethodInvokingJobDetailFactoryBean();
bean.setTargetBeanName("myJob1");
bean.setTargetMethod("sayHello");
return bean;
}
@Bean
JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean bean = new JobDetailFactoryBean();
bean.setJobClass(MyJob2.class);
JobDataMap map = new JobDataMap();
map.put("helloService", helloService());
bean.setJobDataMap(map);
return bean;
}
@Bean
SimpleTriggerFactoryBean simpleTriggerFactoryBean() {
SimpleTriggerFactoryBean bean = new SimpleTriggerFactoryBean();
bean.setStartTime(new Date());
bean.setRepeatCount(5);
bean.setJobDetail(methodInvokingJobDetailFactoryBean().getObject());
bean.setRepeatInterval(3000);
return bean;
}
@Bean
CronTriggerFactoryBean cronTrigger() {
CronTriggerFactoryBean bean = new CronTriggerFactoryBean();
bean.setCronExpression("0/10 * * * * ?");
bean.setJobDetail(jobDetailFactoryBean().getObject());
return bean;
}
@Bean
SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean bean = new SchedulerFactoryBean();
bean.setTriggers(cronTrigger().getObject(), simpleTriggerFactoryBean().getObject());
return bean;
}
@Bean
HelloService helloService() {
return new HelloService();
}
}

关于这个配置说如下几点:

  1. JobDetail 的配置有两种方式:MethodInvokingJobDetailFactoryBean 和 JobDetailFactoryBean 。
  2. 使用 MethodInvokingJobDetailFactoryBean 可以配置目标 Bean 的名字和目标方法的名字,这种方式不支持传参。
  3. 使用 JobDetailFactoryBean 可以配置 JobDetail ,任务类继承自 QuartzJobBean ,这种方式支持传参,将参数封装在 JobDataMap 中进行传递。
  4. Trigger 是指触发器,Quartz 中定义了多个触发器,这里向大家展示其中两种的用法,SimpleTrigger 和 CronTrigger 。
  5. SimpleTrigger 有点类似于前面说的 @Scheduled 的基本用法。
  6. CronTrigger 则有点类似于 @Scheduled 中 cron 表达式的用法。

全部定义完成后,启动 Spring Boot 项目就可以看到定时任务的执行了。

总结

这里主要向大家展示了 Spring Boot 中整合两种定时任务的方法,整合成功之后,剩下的用法基本上就和在 SSM 中使用一致了,不再赘述。本文案例我已经上传到 GitHub ,欢迎大家 star:https://github.com/lenve/javaboy-code-samples

关注公众号【江南一点雨】,专注于 Spring Boot+微服务以及前后端分离等全栈技术,定期视频教程分享,关注后回复 Java ,领取松哥为你精心准备的 Java 干货!

Spring Boot2 系列教程(十六)定时任务的两种实现方式的更多相关文章

  1. Spring Boot2 系列教程 (十六) | 整合 WebSocket 实现广播

    前言 如题,今天介绍的是 SpringBoot 整合 WebSocket 实现广播消息. 什么是 WebSocket ? WebSocket 为浏览器和服务器提供了双工异步通信的功能,即浏览器可以向服 ...

  2. Spring Boot2 系列教程(十二)@ControllerAdvice 的三种使用场景

    严格来说,本文并不算是 Spring Boot 中的知识点,但是很多学过 SpringMVC 的小伙伴,对于 @ControllerAdvice 却并不熟悉,Spring Boot 和 SpringM ...

  3. Spring Boot2 系列教程(十五)定义系统启动任务的两种方式

    在 Servlet/Jsp 项目中,如果涉及到系统任务,例如在项目启动阶段要做一些数据初始化操作,这些操作有一个共同的特点,只在项目启动时进行,以后都不再执行,这里,容易想到web基础中的三大组件( ...

  4. Spring Boot2 系列教程(十)Spring Boot 整合 Freemarker

    今天来聊聊 Spring Boot 整合 Freemarker. Freemarker 简介 这是一个相当老牌的开源的免费的模版引擎.通过 Freemarker 模版,我们可以将数据渲染成 HTML ...

  5. Spring Boot2 系列教程(十八)Spring Boot 中自定义 SpringMVC 配置

    用过 Spring Boot 的小伙伴都知道,我们只需要在项目中引入 spring-boot-starter-web 依赖,SpringMVC 的一整套东西就会自动给我们配置好,但是,真实的项目环境比 ...

  6. Spring Boot2 系列教程 (十八) | 整合 MongoDB

    微信公众号:一个优秀的废人.如有问题,请后台留言,反正我也不会听. 前言 如题,今天介绍下 SpringBoot 是如何整合 MongoDB 的. MongoDB 简介 MongoDB 是由 C++ ...

  7. Spring Boot2 系列教程 (十四) | 统一异常处理

    如题,今天介绍 SpringBoot 是如何统一处理全局异常的.SpringBoot 中的全局异常处理主要起作用的两个注解是 @ControllerAdvice 和 @ExceptionHandler ...

  8. Spring Boot2 系列教程 (十二) | 整合 thymeleaf

    前言 如题,今天介绍 Thymeleaf ,并整合 Thymeleaf 开发一个简陋版的学生信息管理系统. SpringBoot 提供了大量模板引擎,包含 Freemarker.Groovy.Thym ...

  9. Spring Boot2 系列教程 (十) | 实现声明式事务

    前言 如题,今天介绍 SpringBoot 的 声明式事务. Spring 的事务机制 所有的数据访问技术都有事务处理机制,这些技术提供了 API 用于开启事务.提交事务来完成数据操作,或者在发生错误 ...

随机推荐

  1. C++性能查看-宏定义输出

    之前由于想统计代码中每个模块加载时长,因此写了一个模块加载时长统计类,使用起来也是超级方便,只需要定义一个宏即可 使用方式如下: 1.统计函数性能 void func() { CONSUMING_OU ...

  2. Java多线程基础知识例子

    一.管理 1.创建线程 Thread public class Main { public static void main(String[] args) { MyThread myThread = ...

  3. elasticsearch倒排索引与TF-IDF算法

    elasticsearch专栏:https://www.cnblogs.com/hello-shf/category/1550315.html 一.倒排索引(Inverted Index)简介 在关系 ...

  4. SVN更改地址

    因为服务器更改或其他某些原因导致svn地址改变,那么本地应该如何操作tortoiseSVN?如何成功的把项目进行迁移? 操作步骤 1.右击项目目录---TortoiseSVN----重新定位(英文版是 ...

  5. Elastic Static初识(01)

    写在前面 Elastic Static 是指由Elasticsearch,Logstash,Kibana,Beats等组件结合起来而构成的一个数据收集,分析,可视化的一个架构.我们经常听说过的ELK就 ...

  6. javascript:history.go(-1)的使用

    1.问题描述 在微信项目开发中,比如常用联系人的增删改查操作中,比如跳入常用联系人管理页面,选中一个联系人修改它,就会跳入修改页面,修改完成后跳转到常用联系人管理页面,此时如果修改成功跳转采用的是页面 ...

  7. Caused by: com.mysql.jdbc.MysqlDataTruncation: Data truncation: Incorrect datetime value:

    问题:ERROR JDBCExceptionReporter:72 - Data truncation: Incorrect datetime value: '' for column 'create ...

  8. 使用tomcat7发布war项目启动org_apache_tomcat_websocket报错

    在使用tomcat7发布项目时(项目是用springboot 2.1.4.RELEASE版本开发的) 换成tomcat8就可以正常发布了,网上说tomcat7不支持servlet3.1,升级到spri ...

  9. 【ADO.NET基础】加密方法公共类

    各种加密方法集锦: using System; using System.Security.Cryptography; using System.Text; using System.IO; usin ...

  10. Spring Boot (八): Mybatis 增强工具 MyBatis-Plus

    1. 简介 在上一篇文章<Spring Boot (七): Mybatis极简配置> 中我们介绍了在 Spring Boot 中 Mybatis 的基础使用方式,其中有一部分美中不足的是 ...