Java web 应用中常用的两种定时任务解决方案案例
首先对定时任务实现方式做一个总结:
TimerTask ,等于一个线程隔一段时间运行一下。
ScheduledExecutorService ,线程池版的 TimerTask。
Spring 支持的定时任务,@SchSedule注解 ,支持 cron 表达式。
Quartz ,比较流行的任务调度工具,在 SpringMVC 配置起来麻烦,但是在 SpringBoot 中就变得很容易使用。
1、2 两种方案时 Java 最基础的定时任务方案,原理就是线程的执行,TimerTask 为单线程,多个任务无法同时执行。 ScheduledExecutorService 为 TimerTask 补充了线程池,但是在现在来说都很少再去使用这些,3、4 方案最为实用,其中 Spring Task 可以视为轻量级的 Quartz ,简单易用;Quartz 功能全面,simpleSchedule 和 cronSchedule 两种时间表配置方案满足简单和复杂的任务调度方案。
实现方式很简单,SpringBoot 主入添加 @EnableScheduling 注解,具体任务方法使用 @Scheduled 注解
具体代码实现:
主入口:
@EnableScheduling
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
具体任务类:
@Component
public class SpringTask {
@Scheduled(cron = "*/5 * * * * *")//五秒运行一次
public void taskRun(){
System.out.println("Spring task run ——" + new Date());
}
}
cron 的作用就是设定定时任务的执行时间,与 Quartz 的 cronSchedule 使用几乎一样,我们等会一并介绍。
在 SpringBoot 2.0 以后集成 Quartz 变得非常简单,Quartz 有了自己的 starter 依赖。
首先加入依赖包:
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-quartzartifactId>
dependency>
编写具体任务类,需要继承 QuartzJobBean 类:
public class QuartzTask extends QuartzJobBean {
/**
* 定时任务方法
* @param jobExecutionContext
* @throws JobExecutionException
*/
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Quartz Task run --:" + new Date());
}
}
写好继承后,IDEA 中直接用快捷键 ctrl+i 插入重写方法。
然后编写配置类 QuartzConfig ,SpringBoot 中推荐使用 Bean 的方式配置。
@Configuration
public class QuartzConfig {
@Bean
public JobDetail teatQuartzDetail(){
return JobBuilder.newJob(QuartzTask.class).withIdentity("quartzQuartz").storeDurably().build();
}
@Bean
public Trigger testQuartzTrigger(){
// 简单的时间表配置
SimpleScheduleBuilder scheduleBuilder = SimpleScheduleBuilder.simpleSchedule()
.withIntervalInSeconds(10) //设置时间周期单位秒
.repeatForever();
// 需求复杂时使用这种方式
CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule("*/10 * * * * ?");// 十秒运行一次
return TriggerBuilder.newTrigger().forJob(teatQuartzDetail())
.withIdentity("quartzQuartz")
.withSchedule(cronScheduleBuilder)
.build();
}
//多任务的话就声明多个 trigger
}
然后启动项目
Quartz cron 表达式
cron 的表达式是字符串,实际上是由七子表达式,描述个别细节的时间表。
分别代表:
- Seconds
- Minutes
- Hours
- Day-of-Month
- Month
- Day-of-Week
- Year (可选字段)
有效值表:
Seconds (秒) :可以用数字0-59 表示,
Minutes(分) :可以用数字0-59 表示,
Hours(时) :可以用数字0-23表示,
Day-of-Month(天) :可以用数字1-31 中的任一一个值,但要注意一些特别的月份
Month(月) :可以用0-11 或用字符串 “JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV and DEC” 表示
Day-of-Week(每周) :可以用数字1-7表示(1 = 星期日)或用字符口串“SUN, MON, TUE, WED, THU, FRI and SAT”表示
“*”:指定所有的值,比如,Minutes 设置为 *,表示每分钟
“/”:为特别单位,表示为“每”如“0/15”表示每隔15分钟执行一次,“0”表示为从“0”分开始, “3/20”表示表示每隔20分钟执行一次,“3”表示从第3分钟开始执行
“?”:表示每月的某一天,或第周的某一天
“L”:用于每月,或每周,表示为每月的最后一天,或每个月的最后星期几如“6L”表示“每月的最后一个星期五”
“W”:表示为最近工作日,如“15W”放在每月(day-of-month)字段上表示为“到本月15日最近的工作日”
“#”:是用来指定“的”每月第n个工作日,例 在每周(day-of-week)这个字段中内容为"6#3" or “FRI#3” 则表示“每月第三个星期五”表达式示例:
每隔5秒执行一次:*/5 * * * * ?
每隔1分钟执行一次:0 */1 * * * ?
每天23点执行一次:0 0 23 * * ?
每天凌晨1点执行一次:0 0 1 * * ?
每月1号凌晨1点执行一次:0 0 1 1 * ?
每月最后一天23点执行一次:0 0 23 L * ?
每周星期天凌晨1点实行一次:0 0 1 ? * L
在26分、29分、33分执行一次:0 26,29,33 * * * ?
每天的0点、13点、18点、21点都执行一次:0 0 0,13,18,21 * * ?
每天的7点到21点都执行一次:0 0 7-21 * * ?
- 一个专业生成 cron 的网站:cron 生成器
需求简单的话可以直接使用 Spring Task ,比如一个简单的数据对接接口。如果会有复杂的业务需求不如一步到位,直接使用 Quartz。