SpringBoot系列(五)定时任务

1、定时任务

不好意思,本来打算先整合shiro的,但是先用到了定时任务,Shiro的话放在第六节。

1、场景

我们写统计一些数据,利比如:一天的销售量,IP,PV,UV等。这些任务往往需要耗时,我们可以写一个定时任务,把这些任务安排到凌晨去做。

2、概述

在使用 springmvc 中,一般的定时任务是使用 job 或者 quartz 或者timer来实现,但是使用它们的时候比较麻烦,会在 xml 文件中配置很多。
其实我们用的是BOOT框架,但是会讲一下springmvc的配置。

2、定时任务和mvc

2.1 快速入门

测试代码,每间隔一秒自动输出
在web工程下的配置文件applicationContext-config.xml中添加配置

<!‐‐开启任务调度‐‐>
<task:annotation‐driven></task:annotation‐driven>

需要添加命名空间和约束

xmlns:task="http://www.springframework.org/schema/task"
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring‐task.xsd

TestTask类

@Component
public class TestTask{
@Scheduled(cron = "* * * * * ?")
public void orderTimeOutLogic(){
System.out.println("..........");
}
}

运行,就可以看到每秒在控制台输出…

2.2 Cron表达式

简单的说一下我们的七子表达式。(七子,不是妻子。。。)

Cron表达式是一个字符串,字符串以5或6个空格隔开,分开工6或7个域,每一个域代表
一个含义,Cron有如下两种语法
格式:
Seconds Minutes Hours DayofMonth Month DayofWeek Year 或
Seconds Minutes Hours DayofMonth Month DayofWeek

注意:SpringTask不支持第一种格式,也就是说只能写6个域!

代码
Seconds:可出现,- * / 四个字符,有效范围为0-59的整数
Minutes:可出现,- * / 四个字符,有效范围为0-59的整数
Hours:可出现,- * / 四个字符,有效范围为0-23的整数
DayofMonth:可出现,- * / ? L W C八个字符,有效范围为1-31的整数
Month:可出现,- * / 四个字符,有效范围为1-12的整数或JAN-DEc
DayofWeek:可出现,- * / ? L C #四个字符,有效范围为1-7的整数或SUN-SAT两个范围。
1表示星期天,2表示星期一, 依次类推
Year:可出现,- * / 四个字符,有效范围为1970-2099年

每一个域都使用数字,但还可以出现如下特殊字符,它们的含义是:
(1) :表示匹配该域的任意值,假如在Minutes域使用,即表示每分钟都会触发事件。
(2) ?: 只能用在DayofMonth和DayofWeek两个域。它也匹配域的任意值,但实际不会。
因为DayofMonth和DayofWeek会相互影响。
例如想在每月的20日触发调度,不管20日到底是星期几,则只能使用如下写法: 13 13 15 20 * ?,其中最后一位只能用?,而不能使用*,
如果使用*表示不管星期几都会触发,实际上并不是这样。
(3)-:表示范围,例如在Minutes域使用5-20,表示从5分到20分钟每分钟触发一次
(4)/:表示起始时间开始触发,然后每隔固定时间触发一次,例如在Minutes域使用5/20,则意味着5分钟触发一次,而25,45等分别触发一次.
(5),:表示列出枚举值值。例如:在Minutes域使用5,20,则意味着在5和20分每分钟触发一次。
(6)L:表示最后,只能出现在DayofWeek和DayofMonth域,如果在DayofWeek域使用5L,意味着在最后的一个星期四触发。
(7)W:表示有效工作日(周一到周五),只能出现在DayofMonth域,系统将在离指定日期的最近的有效工作日触发事件。
(8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
(9)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。

这些我们不需要记住,只要看到会查 用到能查,就行了。

3、定时任务和springboot

在 application 启动类中使用 @EnableScheduling 注解开启定时任务,会自动扫描,相当于一个开关,把这个开关开完之后,那么只要在相应的任务类中做相应的任务,那么就会被 spring boot 容器扫描到,扫描到后,根据任务定义的时间会自动运行

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

组件

@Component
public class TestTask {
	
	@Scheduled(cron = "*/1 * * * * ?")
	public void test(){
		System.out.println(System.currentTimeMillis());
	}
}

结果
1640494876015
1640494877009
1640494878006
1640494879008
1640494880014
1640494881012
1640494882010
1640494883013
1640494884012
1640494885005
1640494886004
1640494887002
1640494888002
1640494889005
1640494890003
1640494891003
1640494892014
1640494893016
1640494894005
1640494895010
1640494896010
1640494897010
1640494898006
1640494899006
1640494900006
1640494901004
1640494902004
1640494903003
1640494904001
1640494905016
1640494906010
1640494907001

除了支持cron表达式之外还支持:

@Component
public class TestTask {
	
//	@Scheduled(cron = "*/1 * * * * ?")
    @Scheduled(fixedRate = 1000)
	public void test(){
		System.out.println(System.currentTimeMillis());
	}
}

fixedRate: 上一次 启动时间点之后 X秒执行一次
fixedDelay: 上一次 结束时间点之后 每X秒执行一次
initialDelay: 第一次延迟 X秒执行,之后按照fixedRate的规则每X秒执行

这个最好记住

4、分布式系统存在的问题

但是springtask任务在分布式的时候会存在问题:部署多台服务之后,到底哪个服务器执行呢,那么就应该思考代码问题,不管不是timer,还是quatz等都是存在问题的,可能会存在执行多次的问题,这种问题可以采用一下来执行:
1 可以选择代码分离进行单台部署,
2 可以选择redis分布式锁,让一台服务拿到相应的key之后去执行
3 使用zookeeper分布式锁获取单个锁,

其实选择发放许可可以解决这个问题,如果下次遇到了,可以记录一下。

5、结束语

1、总结

其实可以看到,springboot使用定时器注解就可以搞定,更加方便快捷,对于分布式系统,可能会出现问题,可以发放许可解决,至于具体解决方案,下次遇到会记录到专栏中。

2、预告

下次一定是shiro整合springboot。、

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值