springboot集成schedule(深度理解)
背景
在项目开发过程中,我们经常需要执行具有周期性的任务。通过定时任务可以很好的帮助我们实现。
我们拿常用的几种定时任务框架做一个比较:

从以上表格可以看出,Spring Schedule框架功能完善,简单易用。对于中小型项目需求,Spring Schedule是完全可以胜任的。
1、springboot集成schedule
1.1 添加maven依赖包
由于Spring Schedule包含在spring-boot-starter基础模块中了,所有不需要增加额外的依赖。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
1.2 启动类,添加启动注解
在springboot入口或者配置类中增加@EnableScheduling注解即可启用定时任务。
@EnableScheduling
@SpringBootApplication
public class ScheduleApplication {
public static void main(String[] args) {
SpringApplication.run(ScheduleApplication.class, args);
}
}
1.3.添加定时任务
我们将对Spring Schedule三种任务调度器分别举例说明。
1.3.1 Cron表达式
类似于Linux下的Cron表达式时间定义规则。Cron表达式由6或7个空格分隔的时间字段组成,如下图:

常用表达式:

举个栗子:
添加一个work()方法,每10秒执行一次。
注意:当方法的执行时间超过任务调度频率时,调度器会在下个周期执行。
如:假设work()方法在第0秒开始执行,方法执行了12秒,那么下一次执行work()方法的时间是第20秒。
@Component
public class MyTask {
@Scheduled(cron = "0/10 * * * * *")
public void work() {
// task execution logic
}
}
1.3.2 固定间隔任务
下一次的任务执行时间,是从方法最后一次任务执行结束时间开始计算。并以此规则开始周期性的执行任务。
举个栗子:
添加一个work()方法,每隔10秒执行一次。
例如:假设work()方法在第0秒开始执行,方法执行了12秒,那么下一次执行work()方法的时间是第22秒。
@Scheduled(fixedDelay = 1000*10)
public void work() {
// task execution logic
}
1.3.3 固定频率任务
按照指定频率执行任务,并以此规则开始周期性的执行调度。
举个栗子:
添加一个work()方法,每10秒执行一次。
注意:当方法的执行时间超过任务调度频率时,调度器会在当前方法执行完成后立即执行下次任务。
例如:假设work()方法在第0秒开始执行,方法执行了12秒,那么下一次执行work()方法的时间是第12秒。
@Scheduled(fixedRate = 1000*10)
public void work() {
// task execution logic
}
2、配置TaskScheduler线程池
在实际项目中,我们一个系统可能会定义多个定时任务。那么多个定时任务之间是可以相互独立且可以并行执行的。
通过查看org.springframework.scheduling.config.ScheduledTaskRegistrar源代码,发现spring默认会创建一个单线程池。这样对于我们的多任务调度可能会是致命的,当多个任务并发(或需要在同一时间)执行时,任务调度器就会出现时间漂移,任务执行时间将不确定。
protected void scheduleTasks() {
if (this.taskScheduler == null) {
this.localExecutor = Executors.newSingleThreadScheduledExecutor();
this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
}
//省略...
}
2.1 自定义线程池
新增一个配置类,实现SchedulingConfigurer接口。重写configureTasks方法,通过taskRegistrar设置自定义线程池。
@Configuration
public class ScheduleConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.setScheduler(taskExecutor());
} @Bean(destroyMethod="shutdown")
public Executor taskExecutor() {
return Executors.newScheduledThreadPool(20);
}
}
3、实际应用中的问题
3.1 Web应用中的启动和关闭问题
我们知道通过spring加载或初始化的Bean,在服务停止的时候,spring会自动卸载(销毁)。但是由于线程是JVM级别的,如果用户在Web应用中启动了一个线程,那么这个线程的生命周期并不会和Web应用保持一致。也就是说,即使Web应用停止了,这个线程依然没有结束(死亡)。
解决方法:
1)当前对象是通过spring初始化
spring在卸载(销毁)实例时,会调用实例的destroy方法。通过实现DisposableBean接口覆盖destroy方法实现。在destroy方法中主动关闭线程。
@Component
public class MyTask implements DisposableBean{
@Override
public void destroy() throws Exception {
//关闭线程或线程池
ThreadPoolTaskScheduler scheduler = (ThreadPoolTaskScheduler)applicationContext.getBean("scheduler");
scheduler.shutdown();
}
//省略...
}
2)当前对象不是通过spring初始化(管理)
那么我们可以增加一个Servlet上下文监听器,在Servlet服务停止的时候主动关闭线程。
public class MyTaskListenter implements ServletContextListener{
@Override
public void contextDestroyed(ServletContextEvent arg0) {
//关闭线程或线程池
}
//省略...
}
3.2 分布式部署问题
在实际项目中,我们的系统通常会做集群、分布式或灾备部署。那么定时任务就可能出现并发问题,即同一个任务在多个服务器上同时在运行。
解决方法(分布式锁):
1)通过数据库表锁
2)通过缓存中间件
3)通过Zookeeper实现
总结:
spring schedule给我们提供了一套简单、快速、高效、稳定的定时任务框架。但需要考虑线程的生命周期及分布式部署问题。
如果您觉得这篇文章对您有帮助,还望您在右下角帮忙点个“推荐”,博主感激不尽!
我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2f0jbovt0mtcs
springboot集成schedule(深度理解)的更多相关文章
- springboot集成schedule
背景 在项目开发过程中,我们经常需要执行具有周期性的任务.通过定时任务可以很好的帮助我们实现. 我们拿常用的几种定时任务框架做一个比较: 从以上表格可以看出,Spring Schedule框架功能完善 ...
- springBoot 集成Mysql数据库
springBoot 集成Mysql数据库 前一段时间,我们大体介绍过SpringBoot,想必大家还有依稀的印象.我们先来回顾一下:SpringBoot是目前java世界最流行的一个企业级解决方案框 ...
- Springboot单元测试Junit深度实践
Springboot单元测试Junit深度实践 前言 单元测试的好处估计大家也都知道了,但是大家可以发现在国内IT公司中真正推行单测的很少很少,一些大厂大部分也只是在核心产品推广单测来保障质量,今天这 ...
- Springboot集成cache的key生成策略
代码接上文:深度理解springboot集成redis缓存之源码解析 ## 1.使用SpEL表达式 @Cacheable(cacheNames = "emp",key = &quo ...
- springboot集成Actuator
Actuator监控端点,主要用来监控与管理. 原生端点主要分为三大类:应用配置类.度量指标类.操作控制类. 应用配置类:获取应用程序中加载的配置.环境变量.自动化配置报告等与SpringBoot应用 ...
- SpringBoot集成PageHelper时出现“在系统中发现了多个分页插件,请检查系统配置!”
近日在项目中使用SpringBoot集成PageHelper后,跑单元测试时出现了"在系统中发现了多个分页插件,请检查系统配置!"这个问题. 如下图所示: org.mybatis. ...
- SpringBoot集成Spring Security入门体验
一.前言 Spring Security 和 Apache Shiro 都是安全框架,为Java应用程序提供身份认证和授权. 二者区别 Spring Security:重量级安全框架 Apache S ...
- SpringBoot集成Spring Security(7)——认证流程
文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...
- SpringBoot集成Spring Security(6)——登录管理
文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandler 1.2 CustomAuthenticationFailureHandler 1. ...
随机推荐
- 第一个Polymer应用 - (3)使用数据绑定
原文链接: Step 3: Using data binding翻译日期: 2014年7月7日翻译人员: 铁锚我们创建的个人信息卡还算漂亮,但对整个应用来说,只有一张卡片看起来有点空荡荡的感觉.在本节 ...
- OpenCV图片矩阵操作相关,对png图片操作(多通道)
文献链接: http://www.cnblogs.com/tornadomeet/archive/2012/12/26/2834336.html 下面这个高手,写了个小程序我还没有调试,回头 调试看看 ...
- PS 滤镜——扩散特效, 毛玻璃 效果
%%% Diffuse %%% 扩散效果 clc; clear all; addpath('E:\PhotoShop Algortihm\Image Processing\PS Algori ...
- rails将类常量重构到数据库对应的表中之二
在博文之一中我们将Order中的常量重构到了数据库的表中,也做了一些测试,貌似一切都很完美.可是...梦魔还未开始啊!我们少做了一步测试,就是rake test! 结果惨不忍睹,所有测试都是E,全部出 ...
- JQuery(一)---- JQ的选择器,属性,节点,样式,函数等操作详解
JQuery的基本概念 JQuery是一个javascript库,JQuery凭借着简洁的语法和跨平台的兼容性,极大的简化了js操作DOM.处理事件.执行动画等操作.JQuery强调的理念是:'wri ...
- webpack 4.x 遇到的错误
由于之前重装电脑,很多之前的小Demo 现在都跑不起来.特别是webpack一直在报错. webpack 安装node 全局安装webpack,webpack-cli(一定要全局安装) 项目初始化 w ...
- 春天aopframework实现
Java的代码 包 cn.itcast.day3.aopframework; 进口 java.io.IOException的; 进口 的java.io.InputStream; 进口 java.u ...
- Linux服务器安全审计工具与流程完全指南
http://Linux.chinaitlab.com/server/860516.html 当今许多linux服务器都不是刚刚部署完毕的新机器,有专业的Linux系统管理员进行定期维护,IT技术人员 ...
- svn Server sent unexpected return value (403 Forbidden) in response to CHECKOUT
今天,提交資料到公司svn服務器,但是一直提示 Server sent unexpected return value (403 Forbidden) in response to CHECKOUT ...
- Java在线考试系统(含源码)
本文demo下载和视频教学观看地址:http://www.wisdomdd.cn/Wisdom/resource/articleDetail.htm?resourceId=1076 本实例介绍了在线考 ...