Spring Boot定時(shí)任務(wù)

1.Scheduled定時(shí)任務(wù)器
2.整合Quartz定時(shí)任務(wù)框架
3.cron表達(dá)式

1.Scheduled定時(shí)任務(wù)器

  1. 配置pom
    需要添加scheduled坐標(biāo)
        <!-- 添加Scheduled 坐標(biāo)-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
        </dependency>
  1. 編寫定時(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());
    }
}
  1. 在啟動類中開啟定時(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ù)框架

  1. Quartz 的使用思路
    1)job - 任務(wù)- 你要做什么事?
    2)Trigger - 觸發(fā)器- 你什么時(shí)候去做泌神?
    3)Scheduler - 任務(wù)調(diào)度- 你什么時(shí)候需要去做什么事拷橘?

2. 使用方式(沒有整合SpringBoot)

  1. 配置pom文件,添加Quartz的坐標(biāo)
<dependency>
    <groupId>org.quartz-scheduler</groupId>
    <artifactId>quartz</artifactId>
    <version>2.2.1</version>
</dependency>
  1. 創(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. 編寫測試代碼
    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)

  1. 配置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>
  1. 編寫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;
    }
}
  1. 編寫啟動類
    通過@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)錯:


error

原因:
由于業(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í)行一次

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末粹湃,一起剝皮案震驚了整個(gè)濱河市恐仑,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌为鳄,老刑警劉巖裳仆,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異孤钦,居然都是意外死亡歧斟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門偏形,熙熙樓的掌柜王于貴愁眉苦臉地迎上來静袖,“玉大人,你說我怎么就攤上這事俊扭《映龋” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長捐康。 經(jīng)常有香客問我仇矾,道長,這世上最難降的妖魔是什么解总? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任贮匕,我火速辦了婚禮,結(jié)果婚禮上花枫,老公的妹妹穿的比我還像新娘刻盐。我一直安慰自己澎粟,他們只是感情好农曲,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布厘线。 她就那樣靜靜地躺著磷箕,像睡著了一般朝群。 火紅的嫁衣襯著肌膚如雪胯甩。 梳的紋絲不亂的頭發(fā)上往产,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天呵萨,我揣著相機(jī)與錄音溺蕉,去河邊找鬼伶丐。 笑死,一個(gè)胖子當(dāng)著我的面吹牛疯特,可吹牛的內(nèi)容都是我干的哗魂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼漓雅,長吁一口氣:“原來是場噩夢啊……” “哼录别!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起邻吞,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤组题,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后抱冷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體崔列,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年旺遮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了赵讯。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡耿眉,死狀恐怖边翼,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情鸣剪,我是刑警寧澤组底,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布丈积,位于F島的核電站,受9級特大地震影響斤寇,放射性物質(zhì)發(fā)生泄漏桶癣。R本人自食惡果不足惜拥褂,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一娘锁、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧饺鹃,春花似錦莫秆、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至茄螃,卻和暖如春缝驳,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背归苍。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工用狱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人拼弃。 一個(gè)月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓夏伊,卻偏偏與公主長得像,于是被迫代替她去往敵國和親吻氧。 傳聞我的和親對象是個(gè)殘疾皇子溺忧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355