Springboot整個Quartz實現(xiàn)動態(tài)定時任務(wù)的示例代碼
簡介
Quartz是一款功能強大的任務(wù)調(diào)度器,可以實現(xiàn)較為復雜的調(diào)度功能,如每月一號執(zhí)行、每天凌晨執(zhí)行、每周五執(zhí)行等等,還支持分布式調(diào)度。本文使用Springboot+Mybatis+Quartz實現(xiàn)對定時任務(wù)的增、刪、改、查、啟用、停用等功能。并把定時任務(wù)持久化到數(shù)據(jù)庫以及支持集群。
Quartz的3個基本要素
- Scheduler:調(diào)度器。所有的調(diào)度都是由它控制。
- Trigger: 觸發(fā)器。決定什么時候來執(zhí)行任務(wù)。
- JobDetail & Job: JobDetail定義的是任務(wù)數(shù)據(jù),而真正的執(zhí)行邏輯是在Job中。使用JobDetail + Job而不是Job,這是因為任務(wù)是有可能并發(fā)執(zhí)行,如果Scheduler直接使用Job,就會存在對同一個Job實例并發(fā)訪問的問題。而JobDetail & Job 方式,sheduler每次執(zhí)行,都會根據(jù)JobDetail創(chuàng)建一個新的Job實例,這樣就可以規(guī)避并發(fā)訪問的問題。
如何使用Quartz
1.添加依賴
<dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.3</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.3</version> </dependency>
2.創(chuàng)建配置文件
在maven項目的resource目錄下創(chuàng)建quartz.properties
org.quartz.scheduler.instanceName = MyScheduler org.quartz.scheduler.instanceId = AUTO org.quartz.scheduler.rmi.export = false org.quartz.scheduler.rmi.proxy = false org.quartz.scheduler.wrapJobExecutionInUserTransaction = false #線程池配置 org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool org.quartz.threadPool.threadCount = 10 org.quartz.threadPool.threadPriority = 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true #持久化配置 org.quartz.jobStore.misfireThreshold = 50000 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX #支持集群 org.quartz.jobStore.isClustered = true org.quartz.jobStore.useProperties:true org.quartz.jobStore.clusterCheckinInterval = 15000 #使用weblogic連接Oracle驅(qū)動 org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.oracle.weblogic.WebLogicOracleDelegate #org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate org.quartz.jobStore.tablePrefix = QRTZ_ org.quartz.jobStore.dataSource = qzDS #數(shù)據(jù)源連接信息,quartz默認使用c3p0數(shù)據(jù)源可以被自定義數(shù)據(jù)源覆蓋 org.quartz.dataSource.qzDS.driver = oracle.jdbc.driver.OracleDriver org.quartz.dataSource.qzDS.URL = jdbc:oracle:thin:@localhost:1521/XE org.quartz.dataSource.qzDS.user = root org.quartz.dataSource.qzDS.password = 123456 org.quartz.dataSource.qzDS.maxConnections = 10
說明:在使用quartz做持久化的時候需要用到quartz的11張表,可以去quartz官網(wǎng)下載對應(yīng)版本的quartz,解壓打開docs/dbTables里面有對應(yīng)數(shù)據(jù)庫的建表語句。關(guān)于quartz.properties配置的詳細解釋可以查看quartz官網(wǎng)。另外新建一張表TB_APP_QUARTZ用于存放定時任務(wù)基本信息和描述等信息,定時任務(wù)的增、刪、改、執(zhí)行等功能與此表沒有任何關(guān)系。
quartz的11張表:

//TB_APP_QUARTZ表的實體類
public class AppQuartz {
private Integer quartzId; //id 主鍵
private String jobName; //任務(wù)名稱
private String jobGroup; //任務(wù)分組
private String startTime; //任務(wù)開始時間
private String cronExpression; //corn表達式
private String invokeParam;//需要傳遞的參數(shù)
...省略set get
}
3.Quartz配置
/**
* 創(chuàng)建job 實例工廠,解決spring注入問題,如果使用默認會導致spring的@Autowired 無法注入問題
* @author LLQ
*
*/
@Component
public class JobFactory extends AdaptableJobFactory{
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
//調(diào)用父類的方法
Object jobInstance = super.createJobInstance(bundle);
//進行注入
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
@Configuration
public class SchedulerConfig implements ApplicationListener<ContextRefreshedEvent>{
@Autowired
private JobFactory jobFactory;
@Autowired
@Qualifier("dataSource")
private DataSource primaryDataSource;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
System.out.println("任務(wù)已經(jīng)啟動..."+event.getSource());
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
//獲取配置屬性
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
//在quartz.properties中的屬性被讀取并注入后再初始化對象
propertiesFactoryBean.afterPropertiesSet();
//創(chuàng)建SchedulerFactoryBean
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setQuartzProperties(propertiesFactoryBean.getObject());
//使用數(shù)據(jù)源,自定義數(shù)據(jù)源
factory.setDataSource(this.primaryDataSource);
factory.setJobFactory(jobFactory);
factory.setWaitForJobsToCompleteOnShutdown(true);//這樣當spring關(guān)閉時,會等待所有已經(jīng)啟動的quartz job結(jié)束后spring才能完全shutdown。
factory.setOverwriteExistingJobs(false);
factory.setStartupDelay(1);
return factory;
}
/*
* 通過SchedulerFactoryBean獲取Scheduler的實例
*/
@Bean(name="scheduler")
public Scheduler scheduler() throws IOException {
return schedulerFactoryBean().getScheduler();
}
@Bean
public QuartzInitializerListener executorListener() {
return new QuartzInitializerListener();
}
}
4.創(chuàng)建定時任務(wù)服務(wù)
@Service
public class JobUtil {
@Autowired
@Qualifier("scheduler")
private Scheduler scheduler;
/**
* 新建一個任務(wù)
*
*/
public String addJob(AppQuartz appQuartz) throws Exception {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date=df.parse(appQuartz.getStartTime());
if (!CronExpression.isValidExpression(appQuartz.getCronExpression())) {
return "Illegal cron expression"; //表達式格式不正確
}
JobDetail jobDetail=null;
//構(gòu)建job信息
if("JobOne".equals(appQuartz.getJobGroup())) {
jobDetail = JobBuilder.newJob(JobOne.class).withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).build();
}
if("JobTwo".equals(appQuartz.getJobGroup())) {
jobDetail = JobBuilder.newJob(JobTwo.class).withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).build();
}
//表達式調(diào)度構(gòu)建器(即任務(wù)執(zhí)行的時間,不立即執(zhí)行)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(appQuartz.getCronExpression()).withMisfireHandlingInstructionDoNothing();
//按新的cronExpression表達式構(gòu)建一個新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(appQuartz.getJobName(), appQuartz.getJobGroup()).startAt(date)
.withSchedule(scheduleBuilder).build();
//傳遞參數(shù)
if(appQuartz.getInvokeParam()!=null && !"".equals(appQuartz.getInvokeParam())) {
trigger.getJobDataMap().put("invokeParam",appQuartz.getInvokeParam());
}
scheduler.scheduleJob(jobDetail, trigger);
// pauseJob(appQuartz.getJobName(),appQuartz.getJobGroup());
return "success";
}
/**
* 獲取Job狀態(tài)
* @param jobName
* @param jobGroup
* @return
* @throws SchedulerException
*/
public String getJobState(String jobName, String jobGroup) throws SchedulerException {
TriggerKey triggerKey = new TriggerKey(jobName, jobGroup);
return scheduler.getTriggerState(triggerKey).name();
}
//暫停所有任務(wù)
public void pauseAllJob() throws SchedulerException {
scheduler.pauseAll();
}
//暫停任務(wù)
public String pauseJob(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = new JobKey(jobName, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null) {
return "fail";
}else {
scheduler.pauseJob(jobKey);
return "success";
}
}
//恢復所有任務(wù)
public void resumeAllJob() throws SchedulerException {
scheduler.resumeAll();
}
// 恢復某個任務(wù)
public String resumeJob(String jobName, String jobGroup) throws SchedulerException {
JobKey jobKey = new JobKey(jobName, jobGroup);
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null) {
return "fail";
}else {
scheduler.resumeJob(jobKey);
return "success";
}
}
//刪除某個任務(wù)
public String deleteJob(AppQuartz appQuartz) throws SchedulerException {
JobKey jobKey = new JobKey(appQuartz.getJobName(), appQuartz.getJobGroup());
JobDetail jobDetail = scheduler.getJobDetail(jobKey);
if (jobDetail == null ) {
return "jobDetail is null";
}else if(!scheduler.checkExists(jobKey)) {
return "jobKey is not exists";
}else {
scheduler.deleteJob(jobKey);
return "success";
}
}
//修改任務(wù)
public String modifyJob(AppQuartz appQuartz) throws SchedulerException {
if (!CronExpression.isValidExpression(appQuartz.getCronExpression())) {
return "Illegal cron expression";
}
TriggerKey triggerKey = TriggerKey.triggerKey(appQuartz.getJobName(),appQuartz.getJobGroup());
JobKey jobKey = new JobKey(appQuartz.getJobName(),appQuartz.getJobGroup());
if (scheduler.checkExists(jobKey) && scheduler.checkExists(triggerKey)) {
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
//表達式調(diào)度構(gòu)建器,不立即執(zhí)行
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(appQuartz.getCronExpression()).withMisfireHandlingInstructionDoNothing();
//按新的cronExpression表達式重新構(gòu)建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey)
.withSchedule(scheduleBuilder).build();
//修改參數(shù)
if(!trigger.getJobDataMap().get("invokeParam").equals(appQuartz.getInvokeParam())) {
trigger.getJobDataMap().put("invokeParam",appQuartz.getInvokeParam());
}
//按新的trigger重新設(shè)置job執(zhí)行
scheduler.rescheduleJob(triggerKey, trigger);
return "success";
}else {
return "job or trigger not exists";
}
}
}
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class JonOne implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException{
JobDataMap data=context.getTrigger().getJobDataMap();
String invokeParam =(String) data.get("invokeParam");
//在這里實現(xiàn)業(yè)務(wù)邏輯
}
}
@PersistJobDataAfterExecution
@DisallowConcurrentExecution
@Component
public class JobTwo implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException{
JobDataMap data=context.getTrigger().getJobDataMap();
String invokeParam =(String) data.get("invokeParam");
//在這里實現(xiàn)業(yè)務(wù)邏輯
}
}
說明:每個定時任務(wù)都必須有一個分組,名稱和corn表達式,corn表達式也就是定時任務(wù)的觸發(fā)時間,關(guān)于corn表達式格式以及含義可以參考一些網(wǎng)絡(luò)資源。每個定時任務(wù)都有一個入口類在這里我把類名當成定時任務(wù)的分組名稱,例如:只要創(chuàng)建定時任務(wù)的分組是JobOne的都會執(zhí)行JobOne這個任務(wù)類里面的邏輯。如果定時任務(wù)需要額外的參數(shù)可以使用JobDataMap傳遞參數(shù),當然也可以從數(shù)據(jù)庫中獲取需要的數(shù)據(jù)。@PersistJobDataAfterExecution和@DisallowConcurrentExecution注解是不讓某個定時任務(wù)并發(fā)執(zhí)行,只有等當前任務(wù)完成下一個任務(wù)才會去執(zhí)行。
5.封裝定時任務(wù)接口
@RestController
public class JobController {
@Autowired
private JobUtil jobUtil;
@Autowired
private AppQuartzService appQuartzService;
//添加一個job
@RequestMapping(value="/addJob",method=RequestMethod.POST)
public ReturnMsg addjob(@RequestBody AppQuartz appQuartz) throws Exception {
appQuartzService.insertAppQuartzSer(appQuartz);
result=jobUtil.addJob(appQuartz);
}
//暫停job
@RequestMapping(value="/pauseJob",method=RequestMethod.POST)
public ReturnMsg pausejob(@RequestBody Integer[]quartzIds) throws Exception {
AppQuartz appQuartz=null;
if(quartzIds.length>0){
for(Integer quartzId:quartzIds) {
appQuartz=appQuartzService.selectAppQuartzByIdSer(quartzId).get(0);
jobUtil.pauseJob(appQuartz.getJobName(), appQuartz.getJobGroup());
}
return new ReturnMsg("200","success pauseJob");
}else {
return new ReturnMsg("404","fail pauseJob");
}
}
//恢復job
@RequestMapping(value="/resumeJob",method=RequestMethod.POST)
public ReturnMsg resumejob(@RequestBody Integer[]quartzIds) throws Exception {
AppQuartz appQuartz=null;
if(quartzIds.length>0) {
for(Integer quartzId:quartzIds) {
appQuartz=appQuartzService.selectAppQuartzByIdSer(quartzId).get(0);
jobUtil.resumeJob(appQuartz.getJobName(), appQuartz.getJobGroup());
}
return new ReturnMsg("200","success resumeJob");
}else {
return new ReturnMsg("404","fail resumeJob");
}
}
//刪除job
@RequestMapping(value="/deletJob",method=RequestMethod.POST)
public ReturnMsg deletjob(@RequestBody Integer[]quartzIds) throws Exception {
AppQuartz appQuartz=null;
for(Integer quartzId:quartzIds) {
appQuartz=appQuartzService.selectAppQuartzByIdSer(quartzId).get(0);
String ret=jobUtil.deleteJob(appQuartz);
if("success".equals(ret)) {
appQuartzService.deleteAppQuartzByIdSer(quartzId);
}
}
return new ReturnMsg("200","success deleteJob");
}
//修改
@RequestMapping(value="/updateJob",method=RequestMethod.POST)
public ReturnMsg modifyJob(@RequestBody AppQuartz appQuartz) throws Exception {
String ret= jobUtil.modifyJob(appQuartz);
if("success".equals(ret)) {
appQuartzService.updateAppQuartzSer(appQuartz);
return new ReturnMsg("200","success updateJob",ret);
}else {
return new ReturnMsg("404","fail updateJob",ret);
}
}
//暫停所有
@RequestMapping(value="/pauseAll",method=RequestMethod.GET)
public ReturnMsg pauseAllJob() throws Exception {
jobUtil.pauseAllJob();
return new ReturnMsg("200","success pauseAll");
}
//恢復所有
@RequestMapping(value="/repauseAll",method=RequestMethod.GET)
public ReturnMsg repauseAllJob() throws Exception {
jobUtil.resumeAllJob();
return new ReturnMsg("200","success repauseAll");
}
}
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
- SpringBoot設(shè)置動態(tài)定時任務(wù)的方法詳解
- Springboot自帶定時任務(wù)實現(xiàn)動態(tài)配置Cron參數(shù)方式
- 淺談SpringBoot集成Quartz動態(tài)定時任務(wù)
- 基于Springboot執(zhí)行多個定時任務(wù)并動態(tài)獲取定時任務(wù)信息
- SpringBoot實現(xiàn)動態(tài)定時任務(wù)
- 詳解SpringBoot 創(chuàng)建定時任務(wù)(配合數(shù)據(jù)庫動態(tài)執(zhí)行)
- springboot整合Quartz實現(xiàn)動態(tài)配置定時任務(wù)的方法
- SpringBoot實現(xiàn)動態(tài)增刪啟停定時任務(wù)的方式
相關(guān)文章
Spring AOP攔截-三種方式實現(xiàn)自動代理詳解
這篇文章主要介紹了Spring AOP攔截-三種方式實現(xiàn)自動代理詳解,還是比較不錯的,這里分享給大家,供需要的朋友參考。2017-11-11
SpringCloud的網(wǎng)關(guān)Zuul和Gateway詳解
SpringCloudZuul和SpringCloudGateway都是用于構(gòu)建微服務(wù)架構(gòu)中的API網(wǎng)關(guān)的組件,但SpringCloudGateway在性能、功能特性和生態(tài)支持等方面有一些優(yōu)勢,因此推薦使用SpringCloudGateway作為首選2025-02-02
java整數(shù)(秒數(shù))轉(zhuǎn)換為時分秒格式的示例
這篇文章主要介紹了java整數(shù)(秒數(shù))轉(zhuǎn)換為時分秒格式的示例,需要的朋友可以參考下2014-04-04
Java POI實現(xiàn)將導入Excel文件的示例代碼
這篇文章主要介紹了Java POI實現(xiàn)將導入Excel文件的示例代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-02-02
SpringCloud學習筆記之SpringCloud搭建父工程的過程圖解
SpringCloud是分布式微服務(wù)架構(gòu)的一站式解決方案,十多種微服務(wù)架構(gòu)落地技術(shù)的集合體,俗稱微服務(wù)全家桶,這篇文章主要介紹了SpringCloud學習筆記(一)搭建父工程,需要的朋友可以參考下2021-10-10

