Spring Boot定時任務應用實踐

在Spring Boot中實現定時任務功能,能夠經過Spring自帶的定時任務調度,也能夠經過集成經典開源組件Quartz實現任務調度。html

1、Spring定時器

一、cron表達式方式

使用自帶的定時任務,很是簡單,只須要像下面這樣,加上註解就好,不須要像普通定時任務框架那樣繼承任何定時處理接口 ,簡單示例代碼以下:java

複製代碼
package com.power.demo.scheduledtask.simple;

import com.power.demo.util.DateTimeUtil;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
@EnableScheduling
public class SpringTaskA {

    /**
     * CRON表達式參考:http://cron.qqe2.com/
     **/
    @Scheduled(cron = "*/5 * * * * ?", zone = "GMT+8:00")
    private void timerCron() {

        try {
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(String.format("(timerCron)%s 每隔5秒執行一次,記錄日誌", DateTimeUtil.fmtDate(new Date())));

    }

}
複製代碼

上述代碼中,在一個類上添加@EnableScheduling註解,在方法上加上@Scheduled,配置下cron表達式,一個最最簡單的cron定時任務就完成了。cron表達式的各個組成部分,能夠參考下面:spring

@Scheduled(cron = "[Seconds] [Minutes] [Hours] [Day of month] [Month] [Day of week] [Year]")

二、fixedRate和fixedDelay

@Scheduled註解除了cron表達式,還有其餘配置方式,好比fixedRate和fixedDelay,下面這個示例經過配置方式的不一樣,實現不一樣形式的定時任務調度,示例代碼以下:服務器

複製代碼
package com.power.demo.scheduledtask.simple;

import com.power.demo.util.DateTimeUtil;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
@EnableScheduling
public class SpringTaskB {

    /*fixedRate:上一次開始執行時間點以後5秒再執行*/
    @Scheduled(fixedRate = 5000)
    public void timerFixedRate() {

        try {
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(String.format("(fixedRate)如今時間:%s", DateTimeUtil.fmtDate(new Date())));
    }

    /*fixedDelay:上一次執行完畢時間點以後5秒再執行*/
    @Scheduled(fixedDelay = 5000)
    public void timerFixedDelay() {

        try {
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(String.format("(fixedDelay)如今時間:%s", DateTimeUtil.fmtDate(new Date())));

    }

    /*第一次延遲2秒後執行,以後按fixedDelay的規則每5秒執行一次*/
    @Scheduled(initialDelay = 2000, fixedDelay = 5000)
    public void timerInitDelay() {

        try {
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(String.format("(initDelay)如今時間:%s", DateTimeUtil.fmtDate(new Date())));
    }

}
複製代碼

注意一下主要區別:app

@Scheduled(fixedRate = 5000) :上一次開始執行時間點以後5秒再執行框架

@Scheduled(fixedDelay = 5000) :上一次執行完畢時間點以後5秒再執行ide

@Scheduled(initialDelay=2000, fixedDelay=5000) :第一次延遲2秒後執行,以後按fixedDelay的規則每5秒執行一次測試

有時候,不少項目咱們都須要配置好定時任務後當即執行一次,initialDelay就能夠不用配置了。spa

三、zone

@Scheduled註解還有一個熟悉的屬性zone,表示時區,一般,若是不寫,定時任務將使用服務器的默認時區;若是你的任務想在特定時區特定時間點跑起來,好比常見的多語言系統可能會定時跑腳本更新數據,就能夠設置一個時區,如東八區,就能夠設置爲:3d

zone = "GMT+8:00"

2、Quartz

Quartz是應用最爲普遍的開源任務調度框架之一,有不少公司都根據它實現本身的定時任務管理系統。Quartz提供了最經常使用的兩種定時任務觸發器,即SimpleTrigger和CronTrigger,本文以最普遍使用的CronTrigger爲例。

一、添加依賴

        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
            <version>2.3.0</version>
        </dependency>

二、配置cron表達式

示例代碼須要,在application.properties文件中新增以下配置:

  cron-config

其實,咱們徹底能夠不用配置,直接在代碼裏面寫或者持久化在DB中而後讀取也能夠。

三、添加定時任務實現

任務1:

複製代碼
package com.power.demo.scheduledtask.quartz;

import com.power.demo.util.DateTimeUtil;
import org.quartz.DisallowConcurrentExecution;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

import java.util.Date;


@DisallowConcurrentExecution
public class QuartzTaskA implements Job {

    @Override
    public void execute(JobExecutionContext var1) throws JobExecutionException {
        try {
            Thread.sleep(1);
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println(String.format("(QuartzTaskA)%s 每隔3秒執行一次,記錄日誌", DateTimeUtil.fmtDate(new Date())));

    }
}
複製代碼

任務2:

  QuartzTaskB

定時發送郵件任務:

  MailSendTask

實現任務看上去很是簡單,繼承Quartz的Job接口,重寫execute方法便可。

四、集成Quartz定時任務

怎麼讓Spring自動識別初始化Quartz定時任務實例呢?這就須要引用Spring管理的Bean,向Spring容器暴露所必須的bean,經過定義Job Factory實現自動注入。

首先,添加Spring注入的Job Factory類:

複製代碼
package com.power.demo.scheduledtask.quartz.config;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.scheduling.quartz.SpringBeanJobFactory;

public final class AutowireBeanJobFactory extends SpringBeanJobFactory
        implements ApplicationContextAware {

    private transient AutowireCapableBeanFactory beanFactory;

    /**
     * Spring提供了一種機制讓你能夠獲取ApplicationContext,即ApplicationContextAware接口
     * 對於一個實現了ApplicationContextAware接口的類,Spring會實例化它的同時調用它的
     * public voidsetApplicationContext(ApplicationContext applicationContext) throws BeansException;接口,
     * 將該bean所屬上下文傳遞給它。
     **/
    @Override
    public void setApplicationContext(final ApplicationContext context) {
        beanFactory = context.getAutowireCapableBeanFactory();
    }

    @Override
    protected Object createJobInstance(final TriggerFiredBundle bundle)
            throws Exception {
        final Object job = super.createJobInstance(bundle);
        beanFactory.autowireBean(job);
        return job;
    }
}
複製代碼

定義QuartzConfig:

複製代碼
package com.power.demo.scheduledtask.quartz.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
public class QuartzConfig {

    @Autowired
    @Qualifier("quartzTaskATrigger")
    private CronTriggerFactoryBean quartzTaskATrigger;

    @Autowired
    @Qualifier("quartzTaskBTrigger")
    private CronTriggerFactoryBean quartzTaskBTrigger;

    @Autowired
    @Qualifier("mailSendTrigger")
    private CronTriggerFactoryBean mailSendTrigger;

    //Quartz中的job自動注入spring容器託管的對象
    @Bean
    public AutowireBeanJobFactory autoWiringSpringBeanJobFactory() {
        return new AutowireBeanJobFactory();
    }

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
        scheduler.setJobFactory(autoWiringSpringBeanJobFactory());  //配置Spring注入的Job類

        //設置CronTriggerFactoryBean,設定任務Trigger
        scheduler.setTriggers(
                quartzTaskATrigger.getObject(),
                quartzTaskBTrigger.getObject(),
                mailSendTrigger.getObject()
        );
        return scheduler;
    }

}
複製代碼

接着配置job明細:

複製代碼
package com.power.demo.scheduledtask.quartz.config;

import com.power.demo.common.AppField;
import com.power.demo.scheduledtask.quartz.MailSendTask;
import com.power.demo.scheduledtask.quartz.QuartzTaskA;
import com.power.demo.scheduledtask.quartz.QuartzTaskB;
import com.power.demo.util.ConfigUtil;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;

@Configuration
public class TaskSetting {

    @Bean(name = "quartzTaskA")
    public JobDetailFactoryBean jobDetailAFactoryBean() {
        //生成JobDetail
        JobDetailFactoryBean factory = new JobDetailFactoryBean();
        factory.setJobClass(QuartzTaskA.class);  //設置對應的Job
        factory.setGroup("quartzTaskGroup");
        factory.setName("quartzTaskAJob");
        factory.setDurability(false);
        factory.setDescription("測試任務A");

        return factory;
    }

    @Bean(name = "quartzTaskATrigger")
    public CronTriggerFactoryBean cronTriggerAFactoryBean() {

        String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKA_CRON);

        CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
        //設置JobDetail
        stFactory.setJobDetail(jobDetailAFactoryBean().getObject());
        stFactory.setStartDelay(1000);
        stFactory.setName("quartzTaskATrigger");
        stFactory.setGroup("quartzTaskGroup");
        stFactory.setCronExpression(cron);

        return stFactory;
    }

    @Bean(name = "quartzTaskB")
    public JobDetailFactoryBean jobDetailBFactoryBean() {
        //生成JobDetail
        JobDetailFactoryBean factory = new JobDetailFactoryBean();
        factory.setJobClass(QuartzTaskB.class);  //設置對應的Job
        factory.setGroup("quartzTaskGroup");
        factory.setName("quartzTaskBJob");
        factory.setDurability(false);
        factory.setDescription("測試任務B");

        return factory;
    }

    @Bean(name = "quartzTaskBTrigger")
    public CronTriggerFactoryBean cronTriggerBFactoryBean() {

        String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKB_CRON);

        CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
        //設置JobDetail
        stFactory.setJobDetail(jobDetailBFactoryBean().getObject());
        stFactory.setStartDelay(1000);
        stFactory.setName("quartzTaskBTrigger");
        stFactory.setGroup("quartzTaskGroup");
        stFactory.setCronExpression(cron);

        return stFactory;
    }

    @Bean(name = "mailSendTask")
    public JobDetailFactoryBean jobDetailMailFactoryBean() {
        //生成JobDetail
        JobDetailFactoryBean factory = new JobDetailFactoryBean();
        factory.setJobClass(MailSendTask.class);  //設置對應的Job
        factory.setGroup("quartzTaskGroup");
        factory.setName("mailSendTaskJob");
        factory.setDurability(false);
        factory.setDescription("郵件發送任務");

        return factory;
    }

    @Bean(name = "mailSendTrigger")
    public CronTriggerFactoryBean cronTriggerMailFactoryBean() {

        String cron = ConfigUtil.getConfigVal(AppField.JOB_TASKMAIL_CRON);

        CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
        //設置JobDetail
        stFactory.setJobDetail(jobDetailMailFactoryBean().getObject());
        stFactory.setStartDelay(1000);
        stFactory.setName("mailSendTrigger");
        stFactory.setGroup("quartzTaskGroup");
        stFactory.setCronExpression(cron);

        return stFactory;
    }

}
複製代碼

最後啓動你的Spring Boot定時任務應用,一個完整的基於Quartz調度的定時任務就實現好了。

本文定時任務示例中,有一個定時發送郵件任務MailSendTask,下一篇將分享Spring Boot應用中以MongoDB做爲存儲介質的簡易郵件系統。

 

擴展閱讀:

不少公司都會有本身的定時任務調度框架和系統,在Spring Boot中如何整合Quartz集羣,實現動態定時任務配置?

參考:

http://www.cnblogs.com/vincent0928/p/6294792.html

http://www.cnblogs.com/zhenyuyaodidiao/p/4755649.html

相關文章
相關標籤/搜索