Spring boot開啟定時任務(wù)的三種方式
前言
spring boot進(jìn)行定時任務(wù)一共有三種方式,第一種也就是最簡單的一種:基于注解 (@Scheduled)的方式 ;第二種:基于接口 (SchedulingConfigurer) ;第三種:基于注解設(shè)定多線程定時任務(wù) 。
一、基于注解的方式
首先,打開idea,創(chuàng)建springboot項目,無需引入任何jar,springboot自帶定時。
然后,在啟動類中用注解@EnableScheduling進(jìn)行標(biāo)注,表明此類 存在定時任務(wù)。在定時執(zhí)行的方法之上添加注解
@Scheduled(cron ="*/6 * * * * ?")。
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
@SpringBootApplication
@EnableScheduling
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@Scheduled(cron ="*/6 * * * * ?")
public void sayHello() {
System.out.println("hello");
}
}
點擊啟動,即可看到控制臺6秒輸出一次“hello”。
當(dāng)然,定時任務(wù)也可以放在其他類中。例如創(chuàng)建類Task1。
package com.example.task;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
/**
* @Description
* @ClassName Task1
* @Author User
* @date 2020.06.07 12:24
*/
@Component
public class Task1 {
@Scheduled(cron ="*/1 * * * * ?")
public void sayWord() {
System.out.println("world");
}
}
然后可以看到控制臺的輸出結(jié)果:
圖片
這里有個要注意的細(xì)節(jié),就是啟動類需要能掃描到定時任務(wù)類,否則定時任務(wù)啟動不起來。不僅需要@Component注解,也需要將啟動類位置位于定時任務(wù)類之上。如下圖:
圖片
筆者就是犯了這樣的錯,一直沒啟動起來。
@Scheduled除過cron還有三種方式:fixedRate,fixedDelay,initialDelay
cron:
fixedRate:
@Configuration
@EnableScheduling //開啟定時任務(wù)
public class ScheduleTask1 {
//每3秒執(zhí)行一次
@Scheduled(fixedDelay = 3000)
private void myTasks() {
System.out.println("I do myself per third seconds");
}
}
fixedRate:
@Component
@EnableScheduling //開啟定時任務(wù)
public class ScheduleTask2 {
//每10秒執(zhí)行一次
@Scheduled(fixedRate = 10000)
private void myTasks2() {
System.out.println("我是一個定時任務(wù)");
}
}
initialDelay:
@Component
@EnableScheduling //開啟定時任務(wù)
public class ScheduleTask {
//容器啟動后,延遲10秒后再執(zhí)行一次定時器,以后每10秒再執(zhí)行一次該定時器。
@Scheduled(initialDelay = 10000, fixedRate = 10000)
private void myTasks3() {
System.out.println("我是一個定時任務(wù)3");
}
}
cron解釋
cron
cron 用法跟linux下是一摸一樣的,如果你搞過linux下的定時,那么必然很熟悉。
結(jié)構(gòu)
cron表達(dá)式是一個字符串,分為6或7個域,每兩個域之間用空格分隔,
其語法格式為:"秒域 分域 時域 日域 月域 周域 年域"
取值范圍
常例
本方法的demo地址: https://github.com/SUST-MaZhen/scheduledTask.git
基于接口的方式
使用@Scheduled 注解很方便,但缺點是當(dāng)我們調(diào)整了執(zhí)行周期的時候,需要重啟應(yīng)用才能生效,這多少有些不方便。為了達(dá)到實時生效的效果,那么可以使用接口來完成定時任務(wù),統(tǒng)一將定時器信息存放在數(shù)據(jù)庫中。
在mysql中執(zhí)行一下腳本插入定時任務(wù):
drop table if exists `scheduled`;
create table `scheduled` (
`cron_id` varchar(30) NOT NULL primary key,
`cron_name` varchar(30) NULL,
`cron` varchar(30) NOT NULL
);
insert into `scheduled` values ('1','定時器任務(wù)一','0/6 * * * * ?');
創(chuàng)建一個springboot 項目:我們這里只添加一個mapper,不要bean也不要service以及controller,只是為了演示定時功能而已。demo結(jié)構(gòu):
圖片
數(shù)據(jù)源基本配置:
## mysql數(shù)據(jù)源配置
spring.datasource.url=jdbc:mysql://host:3306/dbname?useUnicode=true&serverTimeznotallow=Asia/Shanghai
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
## Mybatis 配置
# 配置為 com.example.bean 指向?qū)嶓w類包路徑
#mybatis.typeAliasesPackage=com.zhenma.bean
mapper也就是dao:
package com.zhenma.mapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;
@Repository
@Mapper
public interface CronMapper {
@Select("select cron from scheduled where cron_id = #{id}")
public String getCron(int id);
}
task類:
package com.zhenma.scheduled;
import com.zhenma.mapper.CronMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
/**
* @Description
* @ClassName MyTask
* @Author User
* @date 2020.06.07 15:23
*/
@Component
@EnableScheduling
public class MyTask implements SchedulingConfigurer {
@Autowired
protected CronMapper cronMapper;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
scheduledTaskRegistrar.addTriggerTask(() -> process(),
triggerContext -> {
String cron = cronMapper.getCron(1);
if (cron.isEmpty()) {
System.out.println("cron is null");
}
return new CronTrigger(cron).nextExecutionTime(triggerContext);
});
}
private void process() {
System.out.println("基于接口定時任務(wù)");
}
}
運行結(jié)果:
圖片
從結(jié)果中可以看出,是按照每6秒也就是數(shù)據(jù)庫中查詢的結(jié)果來進(jìn)行的。
需求:我現(xiàn)在需要每10秒執(zhí)行一次定時任務(wù),該怎么辦呢?對!只需要修改數(shù)據(jù)庫值即可,server無需重啟。觀察修改后的結(jié)果。
圖片
感覺好(????)??嗨哦。
demo地址:https://github.com/SUST-MaZhen/scheduledtask2.git
四、 基于注解設(shè)定多線程定時任務(wù)
前面講到了@Scheduled執(zhí)行周期任務(wù)會受到上次一個任務(wù)的執(zhí)行時間影響。那么可以開啟多線程執(zhí)行周期任務(wù)。
創(chuàng)建springboot項目,創(chuàng)建一個多線程定時任務(wù)類如下:
package com.example.task;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;
/**
* @Description
* @ClassName MultiThreadTask
* @Author User
* @date 2020.06.07 18:56
*/
@EnableScheduling // 1.開啟定時任務(wù)
@EnableAsync // 2.開啟多線程
@Component
public class MultiThreadTask {
@Async
@Scheduled(fixedDelay = 1000) //間隔1秒
public void first() throws InterruptedException {
System.out.println("第一個定時任務(wù)開始 : " + LocalDateTime.now().toLocalTime() + "\r\n線程 : " + Thread.currentThread().getName());
Thread.sleep(1000 * 10);
}
@Async
@Scheduled(fixedDelay = 2000)
public void second() {
System.out.println("第二個定時任務(wù)開始 : " + LocalDateTime.now().toLocalTime() + "\r\n線程 : " + Thread.currentThread().getName());
}
}
執(zhí)行結(jié)果如下:
圖片
從結(jié)果可以看出:第一個任務(wù)的執(zhí)行時間也不受其本身執(zhí)行時間的限制。兩個任務(wù)也互不影響。
demo地址: https://github.com/SUST-MaZhen/scheduledtash3.git
五、總結(jié)
本文介紹了spring boot創(chuàng)建定時任務(wù)的三種方式,當(dāng)然還有其他方式,例如最近本的定時器來進(jìn)行等等。