在很多应用程序中,经常需要执行定时任务。例如,每天或每月给用户发送账户汇总报表,定期检查并发送系统状态报告,等等。

定时任务我们在使用线程池一节中已经讲到了,Java标准库本身就提供了定时执行任务的功能。在Spring中,使用定时任务更简单,不需要手写线程池相关代码,只需要两个注解即可。

我们还是以实际代码为例,建立工程spring-integration-schedule,无需额外的依赖,我们可以直接在AppConfig中加上@EnableScheduling就开启了定时任务的支持:

@Configuration

@ComponentScan

@EnableWebMvc

@EnableScheduling

@EnableTransactionManagement

@PropertySource({ "classpath:/jdbc.properties", "classpath:/task.properties" })

public class AppConfig {

...

}

接下来,我们可以直接在一个Bean中编写一个public void无参数方法,然后加上@Scheduled注解:

@Component

public class TaskService {

final Logger logger = LoggerFactory.getLogger(getClass());

@Scheduled(initialDelay = 60_000, fixedRate = 60_000)

public void checkSystemStatusEveryMinute() {

logger.info("Start check system status...");

}

}

上述注解指定了启动延迟60秒,并以60秒的间隔执行任务。现在,我们直接运行应用程序,就可以在控制台看到定时任务打印的日志:

2020-06-03 18:47:32 INFO [pool-1-thread-1] c.i.learnjava.service.TaskService - Start check system status...

2020-06-03 18:48:32 INFO [pool-1-thread-1] c.i.learnjava.service.TaskService - Start check system status...

2020-06-03 18:49:32 INFO [pool-1-thread-1] c.i.learnjava.service.TaskService - Start check system status...

如果没有看到定时任务的日志,需要检查:

是否忘记了在AppConfig中标注@EnableScheduling;

是否忘记了在定时任务的方法所在的class标注@Component。

除了可以使用fixedRate外,还可以使用fixedDelay,两者的区别我们已经在使用线程池一节中讲过,这里不再重复。

有的童鞋在实际开发中会遇到一个问题,因为Java的注解全部是常量,写死了fixedDelay=30000,如果根据实际情况要改成60秒怎么办,只能重新编译?

我们可以把定时任务的配置放到配置文件中,例如task.properties:

task.checkDiskSpace=30000

这样就可以随时修改配置文件而无需动代码。但是在代码中,我们需要用fixedDelayString取代fixedDelay:

@Component

public class TaskService {

...

@Scheduled(initialDelay = 30_000, fixedDelayString = "${task.checkDiskSpace:30000}")

public void checkDiskSpaceEveryMinute() {

logger.info("Start check disk space...");

}

}

注意到上述代码的注解参数fixedDelayString是一个属性占位符,并配有默认值30000,Spring在处理@Scheduled注解时,如果遇到String,会根据占位符自动用配置项替换,这样就可以灵活地修改定时任务的配置。

此外,fixedDelayString还可以使用更易读的Duration,例如:

@Scheduled(initialDelay = 30_000, fixedDelayString = "${task.checkDiskSpace:PT2M30S}")

以字符串PT2M30S表示的Duration就是2分30秒,请参考LocalDateTime一节的Duration相关部分。

多个@Scheduled方法完全可以放到一个Bean中,这样便于统一管理各类定时任务。

使用Cron任务

还有一类定时任务,它不是简单的重复执行,而是按时间触发,我们把这类任务称为Cron任务,例如:

每天凌晨2:15执行报表任务;

每个工作日12:00执行特定任务;

……

Cron源自Unix/Linux系统自带的crond守护进程,以一个简洁的表达式定义任务触发时间。在Spring中,也可以使用Cron表达式来执行Cron任务,在Spring中,它的格式是:

秒 分 小时 天 月份 星期 年

年是可以忽略的,通常不写。每天凌晨2:15执行的Cron表达式就是:

0 15 2 * * *

每个工作日12:00执行的Cron表达式就是:

0 0 12 * * MON-FRI

每个月1号,2号,3号和10号12:00执行的Cron表达式就是:

0 0 12 1-3,10 * *

在Spring中,我们定义一个每天凌晨2:15执行的任务:

@Component

public class TaskService {

...

@Scheduled(cron = "${task.report:0 15 2 * * *}")

public void cronDailyReport() {

logger.info("Start daily report task...");

}

}

Cron任务同样可以使用属性占位符,这样修改起来更加方便。

Cron表达式还可以表达每10分钟执行,例如:

0 */10 * * * *

这样,在每个小时的0:00,10:00,20:00,30:00,40:00,50:00均会执行任务,实际上它可以取代fixedRate类型的定时任务。

集成Quartz

在Spring中使用定时任务和Cron任务都十分简单,但是要注意到,这些任务的调度都是在每个JVM进程中的。如果在本机启动两个进程,或者在多台机器上启动应用,这些进程的定时任务和Cron任务都是独立运行的,互不影响。

如果一些定时任务要以集群的方式运行,例如每天23:00执行检查任务,只需要集群中的一台运行即可,这个时候,可以考虑使用Quartz。

Quartz可以配置一个JDBC数据源,以便存储所有的任务调度计划以及任务执行状态。也可以使用内存来调度任务,但这样配置就和使用Spring的调度没啥区别了,额外集成Quartz的意义就不大。

Quartz的JDBC配置比较复杂,Spring对其也有一定的支持。要详细了解Quartz的集成,请参考Spring的文档。

思考:如果不使用Quartz的JDBC配置,多个Spring应用同时运行时,如何保证某个任务只在某一台机器执行?

练习

小结

Spring内置定时任务和Cron任务的支持,编写调度任务十分方便。

java 注解scheduler_使用Scheduler相关推荐

  1. java 注解scheduler_使用spring的@Scheduled注解执行定时任务,启动项目不输出警告

    在applicationContext.xml中添加: xmlns:task="http://www.springframework.org/schema/task" xsi:sc ...

  2. Java注解---通俗易懂

    本文转载于Java注解-最通俗易懂的注解 Annotation 中文译过来就是注解.标释的意思,在 Java 中注解是一个很重要的知识点,但经常还是有点让新手不容易理解. 我个人认为,比较糟糕的技术文 ...

  3. java 注解继承注解_Java注解合并,注解继承

    spring中有时候一个类上面标记很多注解. 实际上Java注解可以进行继承(也就是把多个注解合并成1个) 比如说SpringMVC的注解 @RestController @RequestMappin ...

  4. (原创)JAVA注解应用——实现属性的自动检测

    一.什么是注解 Annotation(注解)是JDK5.0及以后版本引入的新特性.它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查.注解是以'@注解名'在代码中存在的,根据注解参数的个数 ...

  5. 干掉前端!3分钟纯 Java 注解搭个管理系统,我直接好家伙

    最近接触到个新项目,发现它用了一个比较有意思的框架,可以说实现了我刚入行时候的梦想,所以这里马不停蹄的和大家分享下. 我刚开始工作接触的项目都还没做前后端分离,经常需要后端来维护页面,有时候觉得自己好 ...

  6. 学长告诉你 java注解——深入浅出

    Java 注解(Annotation)又称 Java 标注,是 JDK5.0 引入的一种注释机制. Java 语言中的类.方法.变量.参数和包等都可以被标注.和 Javadoc 不同,Java 标注可 ...

  7. Java注解基本原理

    Java注解基本原理 注解目前非常的流行,很多主流框架都支持注解,而且自己编写代码的时候也会尽量的去用注解,一时方便,而是代码更加简洁. 注解的语法比较简单,除了@符号的使用之外,它基本与Java固有 ...

  8. 【Java注解】注解基础

    笔记来源:IMOOC Java注解 注解的分类 按照运行机制分 源码注解:注解只在源码中存在,编译成 .class 文件就不存在了 编译时注解:注解在源码和 .class 文件中都存在 运行时注解:在 ...

  9. Java深度历险:Java注解

    2019独角兽企业重金招聘Python工程师标准>>>     在开发Java程序,尤其是Java EE应用的时候,总是免不了与各种配置文件打交道.以Java EE中典型的S(pri ...

最新文章

  1. 分布式之消息队列复习精讲
  2. OpenYurt — Overview
  3. Android Virtual Device(AVD)屏幕大小调整
  4. Java: System.exit() 与安全策略
  5. Qt控件注册事件过滤器后不显示
  6. Windows Mobile 6.0下实现自绘多种状态按钮(Win32) 续
  7. 前端学习(3055):vue+element今日头条管理-反馈
  8. [Leedcode][JAVA][第41题][缺失的第一个正数][哈希表][数组]
  9. 大量数据+同步+多线程_Vulkan 多线程渲染
  10. 揭秘淘宝286亿海量图片存储与处理架构,互联网营销
  11. git将本地项目推送到腾讯开发者平台上的步骤
  12. menuStrip1动态添加菜单及快捷键
  13. Java 中extends与implements使用方法
  14. excel英文大小写转换
  15. re2正则表达式引擎学习(四)
  16. fna服务器未响应,服务器端口说明
  17. 怎么把PPT转成EXE格式,详细步骤
  18. tf.variable_scope,reuse复用变量
  19. 关于G0、G1、G2、G3的名词解释
  20. 逻辑思维能力测试题归纳总结之计算题

热门文章

  1. 黑马程序员-JAVA基础-IO流之流操作规律及读写转换流
  2. Battle for Wesnoth 1.8.4,开源战斗游戏
  3. muduo 与 boost asio 吞吐量对比
  4. 操作系统信号量与P、V操作 初步认识整理
  5. java摄像头推流_悄摸直播(一)—— 推流器的实现(获取笔记本摄像头画面,转流推流到rtmp服务器)...
  6. python数字图像的行 宽的不同处 cv2.resize(1389,1500) p1列宽 p2 行高 stop2.shape 得(640,960,3) v1列宽 v2 行高 v3 通道数
  7. 超越AlphaZero,DeepMind新算法MuZero登顶Nature | AI日报
  8. 如果没有杜撰,可还有历史?
  9. 大脑天天超负荷,三分天赋,七分练,世间惊现普通脑修炼秘籍
  10. 直播 | Python Web开发者的破局之道