Quartz详解和使用CommandLineRunner在项目启动时初始化定时任务
文章目錄
- Quartz介紹
- 自定義CommandLineRunner類:
- 創建、更新定時任務
- service層
- 自定義QuartzJobBean
- 智能調度組件
- 定時任務實體類:
- mapper接口:
- 時間觸發器的一些寫法
之前與定時任務相關的一個文章記錄:
springboot使用@Scheduled作定時任務詳細用法
Quartz介紹
Quartz是一個完全由java編寫的功能豐富的開源作業調度庫,可以集成到幾乎任何Java應用程序中,小到獨立應用程序,大到大型的電子商務系統。Quartz可以用來創建執行數十,數百乃至數萬個作業的簡單或復雜的計劃;作業的任務被定義為標準的Java組件,它可以執行幾乎任何你可能編程的任務。而且Quartz Scheduler包含許多企業級功能,例如支持JTA事務和集群。
了解一下Quartz中涉及到的幾個類概念:
-
SchedulerFactory:調度器工廠。這是一個接口,用于調度器的創建和管理。示例中使用的是Quartz中的默認實現。
-
Scheduler:任務調度器。它表示一個Quartz的獨立運行容器,里面注冊了多個觸發器(Trigger)和任務實例(JobDetail)。兩者分別通過各自的組(group)和名稱(name)作為容器中定位某一對象的唯一依據,因此組和名稱必須唯一(觸發器和任務實例的組和名稱可以相同,因為對象類型不同)。
-
Job:是一個接口,只有一個方法void execute(JobExecutionContext context),開發者實現該接口定義運行任務,JobExecutionContext類提供了調度上下文的各種信息。Job運行時的信息保存在JobDataMap實例中。
-
JobDetail:Job實例。Quartz在每次執行Job時,都重新創建一個Job實例,所以它不直接接受一個Job的實例,相反它接收一個Job實現類,以便運行時通過newInstance()的反射機制實例化Job。因此需要通過一個類來描述Job的實現類及其它相關的靜態信息,如Job名字、描述、關聯監聽器等信息,JobDetail承擔了這一角色。
-
Trigger
:觸發器,描述觸發Job執行的時間觸發規則。
- SimpleTrigger:當僅需觸發一次或者以固定時間間隔周期執行,SimpleTrigger是最適合的選擇。
- CronTrigger:通過Cron表達式定義出各種復雜時間規則的調度方案:如每早晨9:00執行,周一、周三、周五下午5:00執行等。
整個Quartz運行調度的流程如下:
自定義CommandLineRunner類:
關于CommandLineRunner:平常開發中有可能需要實現在項目啟動后執行的功能,SpringBoot提供的一種簡單的實現方案就是添加一個model并實現CommandLineRunner接口,實現功能的代碼放在實現的run方法中
這個類的run方法String… args是應用啟動的時候可以傳進來的參數,有兩種方式可以傳參
一種是命令行的方式傳參,所以這個接口叫CommandLineRunner
另一種方法是通過IntelliJ IDEA配置參數
命令行傳參
首先將應用打成jar包,然后運行如下命令行,這里傳入三個參數
java -jar MyProject.jar my name is
或者在idea中配置:
代碼:
import com.itheima.pinda.entity.ScheduleJobEntity; import com.itheima.pinda.mapper.ScheduleJobMapper; import com.itheima.pinda.utils.ScheduleUtils; import lombok.extern.slf4j.Slf4j; import org.quartz.CronTrigger; import org.quartz.Scheduler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component;import java.util.List;/*** 在項目啟動時初始化定時任務*/ @Component @Slf4j public class DispatchCommandLineRunner implements CommandLineRunner {@Autowiredprivate Scheduler scheduler;@Autowiredprivate ScheduleJobMapper scheduleJobMapper;@Overridepublic void run(String... args) throws Exception {log.info("開始進行定時任務初始化...");//查詢定時任務表schedule_job中所有的數據List<ScheduleJobEntity> list = scheduleJobMapper.selectList(null);//查詢數據庫for (ScheduleJobEntity scheduleJobEntity : list) {//獲得觸發器對象,調用ScheduleUtils中的方法CronTrigger cronTrigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJobEntity.getId());if(cronTrigger == null){//觸發器對象為空,說明對應的定時任務還沒有創建ScheduleUtils.createScheduleJob(scheduler,scheduleJobEntity);}else{//觸發器對象不為空,說明對應的定時任務已經存在了,此時只需要更新ScheduleUtils.updateScheduleJob(scheduler,scheduleJobEntity);}}} }創建、更新定時任務
上面自定義的CommandLineRunner類中調用了工具類的方法來真正運行任務,需要寫一個定時任務工具類,方便通過jobid得到觸發器key和jobkey、獲得表達式觸發器
在這里創建、更新定時任務、立即執行某個特定任務
service層
@Service public class ScheduleJobServiceImpl extends ServiceImpl<ScheduleJobMapper, ScheduleJobEntity> implements IScheduleJobService {@Autowiredprivate Scheduler scheduler;// 在service層中調用ScheduleUtils.run的方法來立即執行任務 @Override@Transactional(rollbackFor = Exception.class)public void run(String[] ids) {for (String id : ids) {ScheduleUtils.run(scheduler, baseMapper.selectById(id));}}}在controller中調用service的方法
@PutMapping("/run/{id}")@ApiOperation("立即執行")public Result run(@PathVariable String id) {scheduleJobService.run(new String[]{id});return Result.ok();}自定義QuartzJobBean
【QuartzJobBean】:
Quartz Job 接口的簡單實現,應用傳入的 JobDataMap 和 SchedulerContext 作為 bean 屬性值。 這是合適的,因為每次執行都會創建一個新的 Job 實例。 JobDataMap 條目將使用相同的鍵覆蓋 SchedulerContext 條目。
例如,假設 JobDataMap 包含一個值為“5”的鍵“myParam”:然后,Job 實現可以公開一個 int 類型的 bean 屬性“myParam”來接收這樣的值,即方法“setMyParam(int)” . 這也適用于復雜類型,如業務對象等。
在上面的 ScheduleUtils中使用JobBuilder.newJob(ScheduleJob.class)構建了job信息,需要拓展QuartzJobBean自定義一個定時任務類
ScheduleJob 繼承自QuartzJobBean,程序會進入executeInternal來執行定時任務
智能調度組件
編寫智能調度組件DispatchTask,封裝的是智能調度的核心邏輯,此類中需要提供run方法,在前面的ScheduleJob定時任務中通過反射調用此run方法來完成智能調度。
? /*** 智能調度組件*/ @Slf4j @Component("dispatchTask") public class DispatchTask{/*** 智能調度* @param businessId* @param params* @param jobId* @param logId*/public void run(String businessId, String params, String jobId, String logId) {log.info("智能調度正在執行,參數為:{},{},{},{}", businessId, params, jobId, logId);} }定時任務實體類:
@Data @EqualsAndHashCode(callSuper = false) @TableName("schedule_job") public class ScheduleJobEntity implements Serializable {/*** id*/@TableId(value = "id", type = IdType.INPUT)private String id;/*** 創建者*/@TableField(fill = FieldFill.INSERT)private Long creator;/*** 創建時間*/@TableField(fill = FieldFill.INSERT)private Date createDate;/*** spring bean名稱*/private String beanName;/*** 參數*/private String params;/*** cron表達式*/private String cronExpression;/*** 任務狀態 0:暫停 1:正常*/private Integer status;/*** 備注*/private String remark;/*** 業務id 機構id*/private String businessId;/*** 更新者*/@TableField(fill = FieldFill.INSERT_UPDATE)private Long updater;/*** 更新時間*/@TableField(fill = FieldFill.INSERT_UPDATE)private Date updateDate; }mapper接口:
/*** 定時任務 Mapper 接口*/ @Component @Mapper public interface ScheduleJobMapper extends BaseMapper<ScheduleJobEntity> {}定時任務在配置成功后啟動時會查詢數據庫,在控制臺輸出類似如下的相應內容:(會查詢數據庫,執行用戶定義的定時任務)
時間觸發器的一些寫法
具體時間設定可參考
“0/10 * * * * ?” 每10秒觸發
“0 0 12 * * ?” 每天中午12點觸發
“0 15 10 ? * *” 每天上午10:15觸發
“0 15 10 * * ?” 每天上午10:15觸發
"0 15 10 * * ? " 每天上午10:15觸發
“0 15 10 * * ? 2005” 2005年的每天上午10:15觸發
“0 * 14 * * ?” 在每天下午2點到下午2:59期間的每1分鐘觸發
“0 0/5 14 * * ?” 在每天下午2點到下午2:55期間的每5分鐘觸發
“0 0/5 14,18 * * ?” 在每天下午2點到2:55期間和下午6點到6:55期間的每5分鐘觸發
“0 0-5 14 * * ?” 在每天下午2點到下午2:05期間的每1分鐘觸發
“0 10,44 14 ? 3 WED” 每年三月的星期三的下午2:10和2:44觸發
“0 15 10 ? * MON-FRI” 周一至周五的上午10:15觸發
“0 15 10 15 * ?” 每月15日上午10:15觸發
“0 15 10 L * ?” 每月最后一日的上午10:15觸發
“0 15 10 ? * 6L” 每月的最后一個星期五上午10:15觸發
“0 15 10 ? * 6L 2002-2005” 2002年至2005年的每月的最后一個星期五上午10:15觸發
“0 15 10 ? * 6#3” 每月的第三個星期五上午10:15觸發
每隔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 * * ?
總結
以上是生活随笔為你收集整理的Quartz详解和使用CommandLineRunner在项目启动时初始化定时任务的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 自定义configureMessageC
- 下一篇: springboot使用j2cache框