1.Scheduled定時(shí)任務(wù)器
2.整合Quartz定時(shí)任務(wù)框架
3.cron表達(dá)式
1.Scheduled定時(shí)任務(wù)器
- 配置pom
需要添加scheduled坐標(biāo)
<!-- 添加Scheduled 坐標(biāo)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
- 編寫定時(shí)任務(wù)類
2.1 將該類添加注解@Component
2.2 定時(shí)任務(wù)觸發(fā)方式:在定時(shí)任務(wù)方法上添加注解@Scheduled(cron=""), 通過cron表達(dá)式定時(shí)觸發(fā)時(shí)間
@Component
public class ScheduledDemo {
/**
* 定時(shí)任務(wù)方法
*/
@Scheduled(cron = "0/2 * * * * ?")
public void scheduledMethod(){
System.out.println("定時(shí)器被觸發(fā)" + new Date());
}
}
- 在啟動類中開啟定時(shí)任務(wù)的使用
3.1 啟動類默認(rèn)關(guān)閉定時(shí)任務(wù),通過注解@EnableScheduling開啟
@SpringBootApplication
@EnableScheduling
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
2.整合Quartz定時(shí)任務(wù)框架
- Quartz 的使用思路
1)job - 任務(wù)- 你要做什么事?
2)Trigger - 觸發(fā)器- 你什么時(shí)候去做泌神?
3)Scheduler - 任務(wù)調(diào)度- 你什么時(shí)候需要去做什么事拷橘?
2. 使用方式(沒有整合SpringBoot)
- 配置pom文件,添加Quartz的坐標(biāo)
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
</dependency>
- 創(chuàng)建job類
定時(shí)任務(wù)被觸發(fā)時(shí)要執(zhí)行什么內(nèi)容
public class QuartzDemo implements Job {
/**
* 任務(wù)被觸發(fā)時(shí)所執(zhí)行的方法
* @param jobExecutionContext
* @throws JobExecutionException
*/
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Execute..." + new Date());
}
}
- 編寫測試代碼
1)job - 任務(wù)- 你要做什么事气嫁?
2)Trigger - 觸發(fā)器- 你什么時(shí)候去做当窗?
3)Scheduler - 任務(wù)調(diào)度- 你什么時(shí)候需要去做什么事?
Trigger對象的兩個(gè)設(shè)置方式
1.簡單的trigger觸發(fā)時(shí)間: 通過Quartz提供一個(gè)方法來完成簡單的重復(fù)調(diào)用cron
2.按照cron的表達(dá)式來給定觸發(fā)的時(shí)間
public class QuartzMain {
public static void main(String[] args) throws SchedulerException {
// 1. 創(chuàng)建job對象:你要做什么事寸宵?
JobDetail job = JobBuilder.newJob(QuartzDemo.class).build();
// 2. 創(chuàng)建Trigger對象: 在什么時(shí)間做超全?
/**
* 1. 簡單的trigger觸發(fā)時(shí)間: 通過Quartz提供一個(gè)方法來完成簡單的重復(fù)調(diào)用cron
* 2. 按照cron的表達(dá)式來給定觸發(fā)的時(shí)間
*/
// 2.1. 簡單的trigger觸發(fā)時(shí)間: 通過Quartz提供一個(gè)方法來完成簡單的重復(fù)調(diào)用cron
// SimpleTrigger trigger = TriggerBuilder.newTrigger().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(2)).build();
// 2.2. 按照cron的表達(dá)式來給定觸發(fā)的時(shí)間
Trigger trigger = TriggerBuilder.newTrigger().withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")).build();
// 3. 創(chuàng)建Scheduler對象: 在什么時(shí)間做什么事?
Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
scheduler.scheduleJob(job, trigger);
// 4. 啟動
scheduler.start();
}
}
3. 使用方式(SpringBoot整合Quartz)
- 配置pom文件
<!-- Quartz 坐標(biāo)-->
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.2.1</version>
<exclusions>
<exclusion>
<artifactId>slf4j-api</artifactId>
<groupId>org.slf4j</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- 添加Scheduled 坐標(biāo)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<!-- Sprng tx 坐標(biāo)-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
</dependency>
- 編寫Quartz啟動類
2.1 給該類添加@Configration注解
2.2 創(chuàng)建Job對象-創(chuàng)建Trigger對象-創(chuàng)建Scheduler對象
要給三個(gè)創(chuàng)建對象的方法添加@Bean注解
2.3 創(chuàng)建Trigger對象的兩種方式
@Configuration
public class QuartzConfig {
// 1. 創(chuàng)建job對象
// 2. 創(chuàng)建trigger對象
// 3. 創(chuàng)建Scheduler對象
@Bean
public JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
// 關(guān)聯(lián)我們自己的Job類
factoryBean.setJobClass(QuartzDemo.class);
return factoryBean;
}
// 創(chuàng)建trigger對象方式一:
// @Bean
// public SimpleTriggerFactoryBean simpleTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
// SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
// // 關(guān)聯(lián)JobDetail對象
// factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
// // 該參數(shù)表示一個(gè)執(zhí)行的毫秒數(shù)
// factoryBean.setRepeatInterval(2000);
// // 重復(fù)次數(shù)
// factoryBean.setRepeatCount(5);
// return factoryBean;
// }
// 創(chuàng)建trigger對象方式二:
@Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean){
CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
// 關(guān)聯(lián)JobDetail對象
factoryBean.setJobDetail(jobDetailFactoryBean.getObject());
// 設(shè)置觸發(fā)時(shí)間
factoryBean.setCronExpression("0/2 * * * * ?");
return factoryBean;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean) {
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
// 關(guān)聯(lián)trigger
factoryBean.setTriggers(cronTriggerFactoryBean.getObject());
return factoryBean;
}
}
- 編寫啟動類
通過@EnableScheduling注解讓SpringBoot打開定時(shí)任務(wù)
@SpringBootApplication
@EnableScheduling
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
4.給Job類中注入對象
public class QuartzDemo implements Job {
@Autowired
private UsersService usersService;
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
System.out.println("Execute... " + new Date());
this.usersService.addUsers();
}
}
此時(shí)會報(bào)錯:
原因:
由于業(yè)務(wù)層userService不能注入
在JobDetailFactoryBean方法中
JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
factoryBean.setJobClass(QuartzDemo.class);
實(shí)例化任務(wù)類QuartzDemo時(shí)使用的是AdaptableJobFactory中的cerateJobInstance方法邓馒,是使用反射的方式來實(shí)例化的嘶朱,完全沒有經(jīng)過spring處理,那么spring的IoC容器中也就沒有該對象光酣。
沒有該對象疏遏,那么在QuartzDemo類中也就無法自動注入usersService
解決辦法:
將實(shí)例化的任務(wù)對象手動添加到Spring IoC容器中,并且完成對象的注入
解決步驟
1.編寫一個(gè)MyAdaptableJobFactory 解決該問題
手動編寫一個(gè)方法繼承AdaptableJobFactory方法救军,重寫createJobInstance方法财异,將對象添加到Spring IOC容器中,并完成注入
2.修改QuartzConfig 類
//編寫一個(gè)MyAdaptableJobFactory
@Component("myAdaptableJobFactory")
public class MyAdaptableJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory autowireCapableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object obj = super.createJobInstance(bundle);
// 將obj對象添加到Spring IOC容器中唱遭,并完成注入
this.autowireCapableBeanFactory.autowireBean(obj);
return obj;
}
}
// 修改QuartzConfig 類
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean, MyAdaptableJobFactory myAdaptableJobFactory) {
SchedulerFactoryBean factoryBean = new SchedulerFactoryBean();
// 關(guān)聯(lián)trigger
factoryBean.setTriggers(cronTriggerFactoryBean.getObject());
//
factoryBean.setJobFactory(myAdaptableJobFactory);
return factoryBean;
}
3.cron表達(dá)式
Cron 表達(dá)式是一個(gè)字符串戳寸,分為6 或7 個(gè)域,每一個(gè)域代表一個(gè)含義
Cron 有如下兩種語法格式:
(1) Seconds Minutes Hours Day Month Week Year
(2)Seconds Minutes Hours Day Month Week
一般使用6個(gè)域的
各個(gè)字段的含義
位置 | 時(shí)間域名 | 允許值 | 允許的特殊字符 |
---|---|---|---|
1 | 秒 | 0-59 | , - * / |
2 | 分鐘 | 0-59 | , - * / |
3 | 小時(shí) | 0-23 | , - * / |
4 | 日 | 1-31 | , - * / L W C |
5 | 月 | 1-12 | , - * / |
6 | 星期 | 1-7 | , - * ? / L C # |
7 | 年(可選) | 1970-2099 | , - * / |
- 星號():可用在所有字段中拷泽,表示對應(yīng)時(shí)間域的每一個(gè)時(shí)刻疫鹊,例如,在分鐘字段時(shí)司致,表示“每分鐘”拆吆;
- 問號(?):該字符只在日期和星期字段中使用,它通常指定為“無意義的值”脂矫,相當(dāng)于占位符枣耀;
- 減號(-):表達(dá)一個(gè)范圍,如在小時(shí)字段中使用“10-12”庭再,則表示從10 到12 點(diǎn)捞奕,即10,11,12牺堰;
- 逗號(,):表達(dá)一個(gè)列表值,如在星期字段中使用“MON,WED,FRI”颅围,則表示星期一萌焰,星期三和星期五;
- 斜杠(/):x/y 表達(dá)一個(gè)等步長序列谷浅,x 為起始值扒俯,y 為增量步長值。如在分鐘字段中使用0/15一疯,則
表示為0,15,30 和45 秒撼玄,而5/15 在分鐘字段中表示5,20,35,50,你也可以使用*/y墩邀,它等同于0/y掌猛;
L:該字符只在日期和星期字段中使用,代表“Last”的意思眉睹,但它在兩個(gè)字段中意思不同荔茬。L 在日期
字段中,表示這個(gè)月份的最后一天竹海,如一月的31 號慕蔚,非閏年二月的28 號;如果L 用在星期中斋配,則表示星
期六孔飒,等同于7。但是艰争,如果L 出現(xiàn)在星期字段里坏瞄,而且在前面有一個(gè)數(shù)值X,則表示“這個(gè)月的最后X 天”甩卓,
例如鸠匀,6L 表示該月的最后星期五;W:該字符只能出現(xiàn)在日期字段里逾柿,是對前導(dǎo)日期的修飾缀棍,表示離該日期最近的工作日。例如15W
表示離該月15 號最近的工作日鹿寻,如果該月15 號是星期六睦柴,則匹配14 號星期五诽凌;如果15 日是星期日毡熏,
則匹配16 號星期一;如果15 號是星期二侣诵,那結(jié)果就是15 號星期二痢法。但必須注意關(guān)聯(lián)的匹配日期不能夠
跨月狱窘,如你指定1W,如果1 號是星期六财搁,結(jié)果匹配的是3 號星期一蘸炸,而非上個(gè)月最后的那天。W 字符串
只能指定單一日期尖奔,而不能指定日期范圍搭儒;LW 組合:在日期字段可以組合使用LW,它的意思是當(dāng)月的最后一個(gè)工作日提茁;
井號(#):該字符只能在星期字段中使用淹禾,表示當(dāng)月某個(gè)工作日。如6#3 表示當(dāng)月的第三個(gè)星期五(6
表示星期五茴扁,#3 表示當(dāng)前的第三個(gè))铃岔,而4#5 表示當(dāng)月的第五個(gè)星期三,假設(shè)當(dāng)月沒有第五個(gè)星期三峭火,
忽略不觸發(fā)毁习;C:該字符只在日期和星期字段中使用,代表“Calendar”的意思卖丸。它的意思是計(jì)劃所關(guān)聯(lián)的日期纺且,
如果日期沒有被關(guān)聯(lián),則相當(dāng)于日歷中所有日期稍浆。例如5C 在日期字段中就相當(dāng)于日歷5 日以后的第一天隆檀。
1C 在星期字段中相當(dāng)于星期日后的第一天。例子:
@Scheduled(cron = "0 0 1 1 1 ?")//每年一月的一號的1:00:00 執(zhí)行一次
@Scheduled(cron = "0 0 1 1 1,6 ?") //一月和六月的一號的1:00:00 執(zhí)行一次
@Scheduled(cron = "0 0 1 1 1,4,7,10 ?") //每個(gè)季度的第一個(gè)月的一號的1:00:00 執(zhí)行一次
@Scheduled(cron = "0 0 1 1 * ?")//每月一號1:00:00 執(zhí)行一次
@Scheduled(cron="0 0 1 * * *") //每天凌晨1 點(diǎn)執(zhí)行一次