原创 | Springboot任务
- 2020 年 1 月 14 日
- 筆記
大家好,我是润森。期末已挂,谁来烧纸,挂得我又有动力学习了!

任务
什么叫做任务呢?其实就是类中实现了一个什么功能的方法。
常见的任务就是异步任务,定时任务
异步任务:其实就是一个很特别的方法,这个方法没有返回值(也可以有返回值,后面会说的),但是方法内部的逻辑会耗费很多时间!例如,用户请求每次到controller,要执行到这个异步方法的时候,我们只需要命令一个空闲状态的线程去执行它即可,由于没有返回值不影响后续代码的运行,controller直接去执行后续的代码。这样可以极为迅速的响应用户,用户体验非常好。
异步任务

目录如下
AsyncService.java
import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; /** * @author: 毛利 */ @Service public class AsyncService { //告诉Spring这是一个异步方法 @Async public void hello() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("处理数据中..."); } }
AsyncController
@RestController public class AsyncController { @Autowired AsyncService asyncService; @GetMapping("/hello") public String hello() { asyncService.hello(); return "success"; } }
在Spring中可以在方法上添加@Async注释,以便异步调用该方法。换句话说,调用者将在调用含有@Async注释的方法时立即返回,并且该方法的实际执行将发生在Spring TaskExecutor异步处理器线程中。需要注意的是该注解@Async默认是不会解析的,SpringBoot中需要加上@EnableAsync来启动。
@EnableAsync @SpringBootApplication public class TaskApplication { public static void main(String[] args) { SpringApplication.run(TaskApplication.class, args); } }

访问hello请求无需等待3秒钟
定时任务
在我们平时开发的项目中,定时任务基本属于必不可少的功能,那大家都是怎么做的呢?但我知道的大多都是静态定时任务实现。
基于注解来创建定时任务非常简单,只需几行代码便可完成。实现如下:
import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; @Service @Component public class ScheduledService { /** * second(秒), minute(分), hour(时), day of month(日), month(月), day of week(周几). * 0 * * * * MON-FRI * 【0 0/5 14,18 * * ?】 每天14点整,和18点整,每隔5分钟执行一次 * 【0 15 10 ? * 1-6】 每个月的周一至周六10:15分执行一次 * 【0 0 2 ? * 6L】每个月的最后一个周六凌晨2点执行一次 * 【0 0 2 LW * ?】每个月的最后一个工作日凌晨2点执行一次 * 【0 0 2-4 ? * 1#1】每个月的第一个周一凌晨2点到4点期间,每个整点都执行一次; */ // @Scheduled(cron = "0 * * * * MON-SAT") //@Scheduled(cron = "0,1,2,3,4 * * * * MON-SAT") // @Scheduled(cron = "0-4 * * * * MON-SAT") @Scheduled(cron = "0/5 * * * * *") // 每5秒跑一次 public void hello() { System.out.println("hello ... "); } }
通过在任意类上使用注解@EnableScheduling开启定时任务功能(依笔者最近所用,凡是@Enable开头的貌似都是开启某项功能的注解),开启后可以在任一需要定时执行的方法上使用注解@Scheduled完成配置,项目启动后即可自动按需要执行
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableScheduling; @EnableAsync @EnableScheduling //开启基于注解的定时任务 @SpringBootApplication public class TaskApplication { public static void main(String[] args) { SpringApplication.run(TaskApplication.class, args); } }

Spring Scheduler定时任务使用步骤:
(1)启用对Spring Scheduler的支持:只需要在启动类或者配置类添加
@EnableScheduling;
(2)定义一个Task服务,在类上添加注解:@Component;
(3)创建定时任务:添加方法使用@Scheduled创建定时任务;

Cron表达式
Cron表达式是一个字符串,字符串以5或6个空格隔开,分为6或7个域,每一个域代表一个含义,Cron有如下两种语法格式
(1) Seconds Minutes Hours DayofMonth Month DayofWeek Year
(2)Seconds Minutes Hours DayofMonth Month DayofWeek
一、结构
corn从左到右(用空格隔开):秒 分 小时 月份中的日期 月份 星期中的日期 年份
二、各字段的含义
字段 |
允许值 |
允许的特殊字符 |
---|---|---|
秒(Seconds) |
0~59的整数 |
, – * / 四个字符 |
分(Minutes) |
0~59的整数 |
,- * / 四个字符 |
小时(Hours |
0~23的整数 |
, – * / 四个字符 |
日期(DayofMonth) |
1~31的整数(需要考虑月的天数) |
,- * ? / L W C 八个字符 |
月份(Month) |
1~12的整数或者 JAN-DEC |
,- * / 四个字符 |
星期(DayofWeek) |
1~7的整数或者 SUN-SAT (1=SUN) |
,- * ? / L C # 八个字符 |
年(可选,留空)(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域,系统将在离指定日期的最近的有效工作日触发事件。例如:在 DayofMonth使用5W,如果5日是星期六,则将在最近的工作日:星期五,即4日触发。如果5日是星期天,则在6日(周一)触发;如果5日在星期一到星期五中的一天,则就在5日触发。另外一点,W的最近寻找不会跨过月份 。
(8)LW:这两个字符可以连用,表示在某个月最后一个工作日,即最后一个星期五。
(9)#:用于确定每个月第几个星期几,只能出现在DayofMonth域。例如在4#2,表示某月的第二个星期三。
三、常用表达式例子
(1)0 0 2 1 * ? * 表示在每月的1日的凌晨2点调整任务
(2)0 15 10 ? * MON-FRI 表示周一到周五每天上午10:15执行作业
(3)0 15 10 ? 6L 2002-2006 表示2002-2006年的每个月的最后一个星期五上午10:15执行作
(4)0 0 10,14,16 * * ? 每天上午10点,下午2点,4点
(5)0 0/30 9-17 * * ? 朝九晚五工作时间内每半小时
(6)0 0 12 ? * WED 表示每个星期三中午12点
(7)0 0 12 * * ? 每天中午12点触发
(8)0 15 10 ? * * 每天上午10:15触发
(9)0 15 10 * * ? 每天上午10:15触发
(10)0 15 10 * * ? * 每天上午10:15触发
我也不会,不会去 http://cron.qqe2.com/网站去弄。
结语
灵活运用框架带来的开发便利,相对于使用原生的jdk的方法,如果有一个已经封装好,经过了别人多次的测试使用,又何必去浪费自己的时间去从头造轮子(甚至因为水平不足导致自己写的定时控制程序bug百出)。
再自我介绍一下吧。我叫润森,是一个的学习者,分享自己的所学所得。