欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

SpringBoot集成quartz實(shí)現(xiàn)定時(shí)任務(wù)

 更新時(shí)間:2023年09月06日 08:57:18   作者:bug菌1  
這篇文章主要介紹了如何使用SpringBoot整合Quartz,并將定時(shí)任務(wù)寫入庫中(持久化存儲(chǔ)),還可以任意對(duì)定時(shí)任務(wù)進(jìn)行如刪除、暫停、恢復(fù)等操作,需要的可以了解下

1. 前言

現(xiàn)如今,隨著市場(chǎng)競(jìng)爭(zhēng)加劇,各個(gè)企業(yè)都在不斷尋求提高效率、降低成本的方法,此時(shí)使用自動(dòng)化工具已成為必不可少的選擇。而在眾多的自動(dòng)化工具中,定時(shí)任務(wù)已經(jīng)成為一項(xiàng)必備工具,而Quartz就是一個(gè)非常好用的定時(shí)任務(wù)框架,它的輕量級(jí)、高可靠性、易于使用等特點(diǎn),使得它成為一個(gè)非常受歡迎的定時(shí)任務(wù)框架。而在本篇文章中,我們將會(huì)介紹如何使用SpringBoot整合Quartz,并將定時(shí)任務(wù)寫入庫中(持久化存儲(chǔ)),還可以任意對(duì)定時(shí)任務(wù)進(jìn)行如刪除、暫停、恢復(fù)等操作。

那么,具體如何實(shí)現(xiàn)呢?這將又會(huì)是干貨滿滿的一期,全程無尿點(diǎn)不廢話只抓重點(diǎn)教,具有非常好的學(xué)習(xí)效果,拿好小板凳準(zhǔn)備就坐!希望學(xué)習(xí)的過程中大家認(rèn)真聽好好學(xué),學(xué)習(xí)的途中有任何不清楚或疑問的地方皆可評(píng)論區(qū)留言或私信,bug菌將第一時(shí)間給予解惑,那么廢話不多說,直接開整!Fighting??! 

2. 環(huán)境說明

本地的開發(fā)環(huán)境:

  • 開發(fā)工具:IDEA 2021.3
  • JDK版本: JDK 1.8
  • Spring Boot版本:2.3.1 RELEASE
  • Maven版本:3.8.2

3. 整合Quartz

下面實(shí)現(xiàn)一個(gè)簡單的任務(wù)調(diào)度系統(tǒng),并且將定時(shí)任務(wù)的信息持久化入庫,希望可以幫助到大家,Quartz的非持久化使用本文就不贅述了。

3.1 搭建Spring Boot應(yīng)用

首先,我們需要搭建一個(gè)Spring Boot項(xiàng)目,如果還不會(huì)點(diǎn)這里,此處就不詳細(xì)贅述啦。

3.2 添加依賴

在Spring Boot項(xiàng)目中,我們可以使用Quartz Starter來集成Quartz框架。只需要在pom.xml文件中引入以下依賴即可:

        <!--集成quartz-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-quartz</artifactId>
            <version>2.3.12.RELEASE</version>
        </dependency>

基礎(chǔ)相關(guān)依賴:

       <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--mysql依賴-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <!--util工具類-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.8.1</version>
        </dependency>

3.3 配置Quartz相關(guān)配置文件

然后,我們需要在application.properties文件中配置數(shù)據(jù)源及Quartz相關(guān)配置:

spring:
  datasource:
    name: db_quartz
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/db_quartz?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=UTF8&rewriteBatchedStatements=true
    username: root
    password: 123456
  #quartz配置
  quartz:
    #數(shù)據(jù)存儲(chǔ)方式 默認(rèn)是 MEMORY(內(nèi)存方式)
    job-store-type: jdbc
    properties:
      org:
        quartz:
          scheduler:
            #調(diào)度標(biāo)識(shí)名
            instanceName: clusteredScheduler
            #ID設(shè)置為自動(dòng)獲取 每一個(gè)必須不同
            instanceId: AUTO
          jobStore:
            #數(shù)據(jù)保存方式為持久化
            class: org.quartz.impl.jdbcjobstore.JobStoreTX
            #數(shù)據(jù)庫平臺(tái)
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate
            #表的前綴
            tablePrefix: QRTZ_
            #加入集群
            isClustered: false
            #調(diào)度實(shí)例失效的檢查時(shí)間間隔
            clusterCheckinInterval: 10000
            #設(shè)置為TRUE不會(huì)出現(xiàn)序列化非字符串類到 BLOB 時(shí)產(chǎn)生的類版本問題
            useProperties: false
          threadPool:
            #ThreadPool 實(shí)現(xiàn)的類名
            class: org.quartz.simpl.SimpleThreadPool
            #線程數(shù)量
            threadCount: 5
            #線程優(yōu)先級(jí)
            threadPriority: 5
            #自創(chuàng)建父線程
            threadsInheritContextClassLoaderOfInitializingThread: true

其中,job-store-type表示使用的持久化方式,這里選擇了使用jdbc完成任務(wù)持久化入庫。jdbc的相關(guān)配置包括initialize-schema,comment-prefix,use-properties,table-prefix,scheduler-name等,這里不再贅述,具體的我已在代碼中進(jìn)行了詳細(xì)注釋。

3.4 添加Quartz表

接下來,我們需要?jiǎng)?chuàng)建一個(gè)數(shù)據(jù)庫表,用于存儲(chǔ)任務(wù)信息。在使用quartz做持久化的時(shí)候需要用到quartz的11張表,可以去quartz官網(wǎng)下載對(duì)應(yīng)版本的quartz,你進(jìn)入quartz的官網(wǎng)Quartz Enterprise Job Scheduler,點(diǎn)擊Downloads,若想要現(xiàn)成的,可以去我的github倉庫取https://github.com/luoyong0603/SpringBoot-demos。下載并解壓,打開docs/dbTables里面有對(duì)應(yīng)數(shù)據(jù)庫的建表語句。演示截圖如下:

我這選擇的是mysql數(shù)據(jù)庫且使用innodb引擎,對(duì)應(yīng)的腳本文件是tables_mysql_innodb.sql,這里大家可以自行去了解下innodb與myisam的區(qū)別。這些表不需要我們做任何操作,是Quartz框架使用的。把創(chuàng)表sql執(zhí)行后,就如下這樣了,總共11張表,示例如下:

接下來對(duì)每張表的作用做以下總結(jié),Quartz將Job保存在數(shù)據(jù)庫中所需表的說明:

  • QRTZ_CALENDARS:以 Blob 類型存儲(chǔ) Quartz 的 Calendar 信息 
  • QRTZ_CRON_TRIGGERS:存儲(chǔ) Cron Trigger,包括 Cron表達(dá)式和時(shí)區(qū)信息 
  • QRTZ_FIRED_TRIGGERS:存儲(chǔ)與已觸發(fā)的 Trigger 相關(guān)的狀態(tài)信息,以及相聯(lián) Job的執(zhí)行信息
  • QRTZ_PAUSED_TRIGGER_GRPS:存儲(chǔ)已暫停的 Trigger 組的信息 
  • QRTZ_SCHEDULER_STATE 存儲(chǔ)少量的有關(guān) Scheduler 的狀態(tài)信息,和別的 Scheduler實(shí)例(假如是用于一個(gè)集群中) 
  • QRTZ_LOCKS 存儲(chǔ)程序的悲觀鎖的信息(假如使用了悲觀鎖) 
  • QRTZ_JOB_DETAILS 存儲(chǔ)每一個(gè)已配置的 Job 的詳細(xì)信息 
  • QRTZ_SIMPLE_TRIGGERS 存儲(chǔ)簡單的Trigger,包括重復(fù)次數(shù),間隔,以及已觸的次數(shù) 
  • QRTZ_BLOG_TRIGGERS Trigger 作為 Blob 類型存儲(chǔ)(用于 Quartz 用戶用 JDBC創(chuàng)建他們自己定制的 Trigger 類型,JobStore 并不知道如何存儲(chǔ)實(shí)例的時(shí)候) 
  • QRTZ_TRIGGER_LISTENERS 存儲(chǔ)已配置的 TriggerListener 的信息 
  • QRTZ_TRIGGERS 存儲(chǔ)已配置的 Trigger 的信息 

并對(duì)其中的4張常用表進(jìn)行表結(jié)構(gòu)解讀,輔助大家理解:

表qrtz_job_details: 保存job詳細(xì)信息,該表需要用戶根據(jù)實(shí)際情況初始化 

job_name:集群中job的名字,該名字用戶自己可以隨意定制,無強(qiáng)行要求 

job_group:集群中job的所屬組的名字,該名字用戶自己隨意定制,無強(qiáng)行要求 

job_class_name:集群中個(gè)note job實(shí)現(xiàn)類的完全包名,quartz就是根據(jù)這個(gè)路徑到classpath找到該job類 

is_durable:是否持久化,把該屬性設(shè)置為1,quartz會(huì)把job持久化到數(shù)據(jù)庫中 

job_data:一個(gè)blob字段,存放持久化job對(duì)象 

表qrtz_triggers: 保存trigger信息 

trigger_name: trigger的名字,該名字用戶自己可以隨意定制,無強(qiáng)行要求 

trigger_group:trigger所屬組的名字,該名字用戶自己隨意定制,無強(qiáng)行要求 

job_name: qrtz_job_details表job_name的外鍵 

job_group: qrtz_job_details表job_group的外鍵 

trigger_state:當(dāng)前trigger狀態(tài),設(shè)置為ACQUIRED,如果設(shè)置為WAITING,則job不會(huì)觸發(fā) 

trigger_cron:觸發(fā)器類型,使用cron表達(dá)式 

表qrtz_cron_triggers:存儲(chǔ)cron表達(dá)式表 

trigger_name: qrtz_triggers表trigger_name的外鍵 

trigger_group: qrtz_triggers表trigger_group的外鍵 

cron_expression:cron表達(dá)式 

表qrtz_scheduler_state:存儲(chǔ)集群中note實(shí)例信息,quartz會(huì)定時(shí)讀取該表的信息判斷集群中每個(gè)實(shí)例的當(dāng)前狀態(tài) 

instance_name:之前配置文件中org.quartz.scheduler.instanceId配置的名字,就會(huì)寫入該字段,如果設(shè)置為AUTO,quartz會(huì)根據(jù)物理機(jī)名和當(dāng)前時(shí)間產(chǎn)生一個(gè)名字 

last_checkin_time:上次檢查時(shí)間 

checkin_interval:檢查間隔時(shí)間

3.5 創(chuàng)建Controller

這里我們創(chuàng)建個(gè)QuartzController控制器,用來添加多個(gè)操作Quartz的請(qǐng)求方式,例如:刪除定時(shí)任務(wù)、暫停定時(shí)任務(wù)、查看所有定時(shí)任務(wù)等。Swagger示例截圖如下:

示例代碼如下:僅供參考,有想法的也可以拓展或者修改。

@RestController
@RequestMapping("/quartz")
public class QuartzController {
    @Autowired
    private QuartzService quartzService;
    /**
     * 新增任務(wù)
     */
    @PostMapping("/insert")
    @ApiOperation(value = "新增任務(wù)", notes = "新增任務(wù)")
    public Boolean insertTask(@RequestBody QuartzModel quartzModel) {
        return quartzService.addJob(quartzModel);
    }
    /**
     * 暫停任務(wù)
     */
    @PostMapping("/pause")
    @ApiOperation(value = "暫停任務(wù)", notes = "暫停任務(wù)")
    public Boolean pauseTask(@RequestBody OperationModel operationModel) {
        return quartzService.pauseJob(operationModel);
    }
    /**
     * 恢復(fù)任務(wù)
     */
    @PostMapping("/resume")
    @ApiOperation(value = "恢復(fù)任務(wù)", notes = "恢復(fù)任務(wù)")
    public Boolean resumeTask(@RequestBody OperationModel operationModel) {
        return quartzService.resumeJob(operationModel);
    }
    /**
     * 刪除任務(wù)
     */
    @PostMapping("/delete")
    @ApiOperation(value = "刪除任務(wù)", notes = "刪除任務(wù)")
    public Boolean deleteTask(@RequestBody OperationModel operationModel) {
        return quartzService.deleteJob(operationModel);
    }
    /**
     * 查看所有定時(shí)任務(wù)
     */
    @GetMapping("/query-all-job")
    @ApiOperation(value = "查看所有定時(shí)任務(wù)", notes = "查看所有定時(shí)任務(wù)")
    public List<Map<String, Object>> queryAllJob() {
        return quartzService.queryAllJob();
    }
    /**
     * 查看正在運(yùn)行的任務(wù)
     */
    @GetMapping("/query-all-running-job")
    @ApiOperation(value = "查看正在執(zhí)行的任務(wù)", notes = "查看正在執(zhí)行的任務(wù)")
    public List<Map<String, Object>> queryAllRunningJob() {
        return quartzService.queryAllRunningJob();
    }
}

3.6 編寫QuartzService接口

這里將被定義所對(duì)應(yīng)的接口,用于操作Quartz任務(wù)。

@Service
public interface QuartzService {
    /**
     * 新增定時(shí)任務(wù)
     */
    Boolean addJob(QuartzModel quartzModel);
    /**
     * 暫停定時(shí)任務(wù)
     */
    Boolean pauseJob(OperationModel operationModel);
    /**
     * 繼續(xù)定時(shí)任務(wù)
     */
    Boolean resumeJob(OperationModel operationModel);
    /**
     * 刪除定時(shí)任務(wù)
     */
    Boolean deleteJob(OperationModel operationModel);
    /**
     * 查詢所有計(jì)劃中的任務(wù)列表
     */
    List<Map<String, Object>> queryAllJob();
    /**
     * 查看正在運(yùn)行的任務(wù)
     */
    List<Map<String, Object>> queryAllRunningJob();
}

3.7 實(shí)現(xiàn)定時(shí)任務(wù)執(zhí)行器

這里我們手動(dòng)寫任務(wù)執(zhí)行器,目的不僅是為了執(zhí)行定時(shí)任務(wù)也想通過區(qū)分定時(shí)任務(wù)執(zhí)行不同的邏輯,示例代碼如下,僅供參考:

 
/**
 * 定時(shí)任務(wù)執(zhí)行器
 */
@Slf4j
public class TaskDistributor extends QuartzJobBean {
    /**
     * 根據(jù)不同的jobDetail攜帶的type參數(shù)區(qū)分,執(zhí)行不同業(yè)務(wù)
     */
    @Override
    protected void executeInternal(JobExecutionContext context) {
        synchronized (this) {
            log.info("開始執(zhí)行定時(shí)任務(wù)...............");
            try {
                //獲取job中攜帶的內(nèi)容并轉(zhuǎn)成jobDetailModel對(duì)象
                JobDetailModel jobDetailModel = (JobDetailModel) context.getJobDetail().getJobDataMap().get("jobDetailModel");
                Integer type = jobDetailModel.getType();
                String content = jobDetailModel.getContent();
                //根據(jù)type執(zhí)行不同的業(yè)務(wù)邏輯
                switch (type) {
                    case 1:
                        System.out.println("task1即將被執(zhí)行,content:" + content);
                        //模擬處理邏輯
                        Thread.sleep(5000);
                        log.info("---------task1定時(shí)任務(wù)執(zhí)行結(jié)束----------");
                        break;
                    case 2:
                        System.out.println("task2即將被執(zhí)行,content:" + content);
                        //模擬處理邏輯
                        Thread.sleep(5000);
                        log.info("----------task2定時(shí)任務(wù)結(jié)束---------");
                        break;
                    default:
                        log.info("---------定時(shí)任務(wù)執(zhí)行開始----------");
                        log.info("---------定時(shí)任務(wù)執(zhí)行結(jié)束----------");
                        break;
                }
            } catch (Throwable t) {
                log.error(t.getMessage(), t);
            }
            log.info("定時(shí)任務(wù)執(zhí)行結(jié)束...............");
        }
    }
}

3.8 創(chuàng)建QuartzServiceImpl實(shí)現(xiàn)類

這里我們將QuartzService接口中的所有接口進(jìn)行實(shí)現(xiàn),示例代碼如下:

@Slf4j
@Service
public class QuartzServiceImpl implements QuartzService {
    @Autowired
    private Scheduler scheduler;
    /**
     * 新增定時(shí)任務(wù)
     */
    @Override
    public Boolean addJob(QuartzModel quartzModel) {
        try {
            String cron = quartzModel.getCron();
            //校驗(yàn)cron是否有效
            boolean valid = CronUtils.isValid(cron);
            if (!valid) {
                return false;
            }
            JobDetail jobDetail = JobBuilder.newJob(TaskDistributor.class)
                    .withIdentity(quartzModel.getJobName(), quartzModel.getJobGroup())
                    .build();
            // 攜帶job內(nèi)容 此處可以攜帶業(yè)務(wù)所需要的執(zhí)行參數(shù)
            JobDetailModel jobDetailModel = quartzModel.getJobData();
            if (!Objects.isNull(jobDetailModel)) {
                jobDetail.getJobDataMap().put("jobDetailModel", jobDetailModel);
            }
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity(quartzModel.getTriggerName(), quartzModel.getTriggerGroup())
                    .startNow()
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                    .build();
            //把作業(yè)和觸發(fā)器注冊(cè)到任務(wù)調(diào)度中
            scheduler.scheduleJob(jobDetail, trigger);
            //啟用調(diào)度
            scheduler.start();
            log.info("---------定時(shí)任務(wù)成功添加進(jìn)quartz隊(duì)列中!----------");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
    /**
     * 暫停定時(shí)任務(wù)
     */
    @Override
    public Boolean pauseJob(OperationModel operationModel) {
        try {
            scheduler.pauseJob(JobKey.jobKey(operationModel.getJobName(), operationModel.getJobGroup()));
            System.out.println("暫停定時(shí)任務(wù)成功");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return true;
    }
    /**
     * 繼續(xù)定時(shí)任務(wù)
     */
    @Override
    public Boolean resumeJob(OperationModel operationModel) {
        try {
            scheduler.resumeJob(JobKey.jobKey(operationModel.getJobName(), operationModel.getJobGroup()));
            System.out.println("恢復(fù)定時(shí)任務(wù)成功");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return true;
    }
    /**
     * 刪除定時(shí)任務(wù)
     */
    @Override
    public Boolean deleteJob(OperationModel operationModel) {
        try {
            // TriggerKey 定義了trigger的名稱和組別 ,通過任務(wù)名和任務(wù)組名獲取TriggerKey
            TriggerKey triggerKey = TriggerKey.triggerKey(operationModel.getJobName(), operationModel.getJobGroup());
            // 停止觸發(fā)器
            scheduler.resumeTrigger(triggerKey);
            // 移除觸發(fā)器
            scheduler.unscheduleJob(triggerKey);
            scheduler.deleteJob(JobKey.jobKey(operationModel.getJobName(), operationModel.getJobGroup()));
            System.out.println("刪除定時(shí)任務(wù)成功");
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return true;
    }
    /**
     * 查看所有定時(shí)任務(wù)
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> queryAllJob() {
        List<Map<String, Object>> jobList = null;
        try {
            GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup();
            Set<JobKey> jobKeys = scheduler.getJobKeys(matcher);
            jobList = new ArrayList<Map<String, Object>>();
            for (JobKey jobKey : jobKeys) {
                List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
                for (Trigger trigger : triggers) {
                    jobList.add(this.buildMap(jobKey, trigger));
                }
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return jobList;
    }
    /**
     * 返回指定的map集合
     */
    private Map<String, Object> buildMap(JobKey jobKey, Trigger trigger) throws SchedulerException {
        Map<String, Object> map = new HashMap<>();
        map.put("jobName", jobKey.getName());
        map.put("jobGroupName", jobKey.getGroup());
        map.put("description", "觸發(fā)器:" + trigger.getKey());
        Trigger.TriggerState triggerState = scheduler.getTriggerState(trigger.getKey());
        map.put("jobStatus", triggerState.name());
        if (trigger instanceof CronTrigger) {
            CronTrigger cronTrigger = (CronTrigger) trigger;
            String cronExpression = cronTrigger.getCronExpression();
            map.put("jobTime", cronExpression);
        }
        return map;
    }
    /**
     * 獲取所有正在運(yùn)行的job
     *
     * @return
     */
    @Override
    public List<Map<String, Object>> queryAllRunningJob() {
        List<Map<String, Object>> jobList = null;
        try {
            List<JobExecutionContext> executingJobs = scheduler.getCurrentlyExecutingJobs();
            jobList = new ArrayList<Map<String, Object>>(executingJobs.size());
            for (JobExecutionContext executingJob : executingJobs) {
                JobDetail jobDetail = executingJob.getJobDetail();
                JobKey jobKey = jobDetail.getKey();
                Trigger trigger = executingJob.getTrigger();
                jobList.add(this.buildMap(jobKey, trigger));
            }
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return jobList;
    }
}

其中addJob方法將一個(gè)定時(shí)任務(wù)添加到調(diào)度器中,其中jobName和jobGroupName表示任務(wù)的名稱和分組名稱,triggerName和triggerGroupName表示觸發(fā)器的名稱和分組名稱,jobClass表示任務(wù)的類,cron表示定時(shí)任務(wù)執(zhí)行的時(shí)間表達(dá)式。scheduler.scheduleJob(jobDetail, trigger);目的是把作業(yè)和觸發(fā)器注冊(cè)到任務(wù)調(diào)度中。

3.9 接口測(cè)試

重啟項(xiàng)目后,我們來進(jìn)行接口的請(qǐng)求測(cè)試,驗(yàn)證我們所添加的定時(shí)任務(wù)是否會(huì)執(zhí)行且被新增入庫持久化保存?就讓我們拭目以待吧! 

如下我直接通過Swagger在線接口文檔作為測(cè)試,測(cè)試如下:

3.9.1 添加定時(shí)任務(wù)task1

具體請(qǐng)求參數(shù)附上:

{
    "cron": "*/10 * * * * ? ",
    "jobData": {
        "content": "bug菌寫定時(shí)任務(wù)(執(zhí)行邏輯1)",
        "type": 1
    },
    "jobGroup": "job_group_task1",
    "jobName": "job_name_task1",
    "triggerGroup": "trigger_group_task1",
    "triggerName": "trigger_task1"

3.9.2 添加定時(shí)任務(wù)task2

具體請(qǐng)求參數(shù)附上:

{
    "cron": "*/20 * * * * ? ",
    "jobData": {
        "content": "bug菌寫定時(shí)任務(wù)(執(zhí)行邏輯2)",
        "type": 2
    },
    "jobGroup": "job_group_task2",
    "jobName": "job_name_task2",
    "triggerGroup": "trigger_group_task2",
    "triggerName": "trigger_task2"

3.9.3 測(cè)試獲取所有的定時(shí)任務(wù)

添加兩個(gè)定時(shí)任務(wù)后,可以查看一下所有定時(shí)任務(wù)列表:

定時(shí)任務(wù)成功添加進(jìn)quartz隊(duì)列中!被插入的定時(shí)任務(wù)task1被成功執(zhí)行且執(zhí)行的type = 1的業(yè)務(wù)邏輯,打印了" task1即將被執(zhí)行,content:bug菌寫定時(shí)任務(wù)(執(zhí)行邏輯1) "

示例截圖如下:

定時(shí)任務(wù)成功添加進(jìn)quartz隊(duì)列中!被插入的定時(shí)任務(wù)task2被成功執(zhí)行且執(zhí)行的type = 2的業(yè)務(wù)邏輯,打印了" task2即將被執(zhí)行,content:bug菌寫定時(shí)任務(wù)(執(zhí)行邏輯2) "

示例截圖如下:

3.9.4 驗(yàn)證數(shù)據(jù)庫是否被保存定時(shí)任務(wù) 

我們?cè)賮頇z查一遍,查驗(yàn)下我們添加的兩條定時(shí)任務(wù)是否被自動(dòng)插入庫中(持久化)。

在上面的兩個(gè)添加任務(wù)的過程中,我們不僅將定時(shí)任務(wù)配置在了代碼中,并把將它們持久化到數(shù)據(jù)庫中。因?yàn)槲覀兙褪窍M趹?yīng)用程序重啟后仍然能夠保持任務(wù)狀態(tài),而Quartz就在內(nèi)部直接將它們持久化到數(shù)據(jù)庫中。

在Quartz中,定時(shí)任務(wù)數(shù)據(jù)是存儲(chǔ)在三張表中的:

  • QRTZ_JOB_DETAILS:保存JobDetail信息
  • QRTZ_TRIGGERS:保存Trigger信息
  • QRTZ_CRON_TRIGGERS:保存CronTrigger信息

當(dāng)我們插入定時(shí)任務(wù)時(shí),Quartz會(huì)自動(dòng)將任務(wù)數(shù)據(jù)存儲(chǔ)到這三張表中。我們插入了兩個(gè)task定時(shí)任務(wù)后,我們完全不需要自主手插入定時(shí)任務(wù),它會(huì)自動(dòng)幫我們保存入庫,同學(xué)們請(qǐng)看:

qrtz_cron_triggers表:

qrtz_job_details表:

qrtz_triggers表:

這樣一來,哪怕是項(xiàng)目重啟,定時(shí)任務(wù)也照常執(zhí)行,不會(huì)因?yàn)闆]有被觸發(fā)而停止執(zhí)行定時(shí)任務(wù)??梢钥吹皆俅沃貑⒑蟮捻?xiàng)目task1與task2都自動(dòng)執(zhí)行,保持了任務(wù)狀態(tài)。

3.9.5 暫停定時(shí)任務(wù)

具體請(qǐng)求參數(shù)附上:

{
    "jobGroup": "job_group_task1_jg",
    "jobName": "job_name_task1_jn"
}

切記,我是為了區(qū)分便在參數(shù)pojo值上手動(dòng)拼接后綴,比如:

可以看到數(shù)據(jù)入庫的都被添加了對(duì)應(yīng)的后綴名。 

所以同學(xué)們?cè)跍y(cè)試接口的時(shí)候,別忘了把后綴加上,或者你們也可以把我的這段去掉。

控制臺(tái)查驗(yàn)是否被暫停了,大家請(qǐng)看:

經(jīng)多次測(cè)試,task1任務(wù)確實(shí)暫停執(zhí)行了。

3.9.6 繼續(xù)定時(shí)任務(wù)

我們能暫停任務(wù),就能把被暫停的任務(wù)恢復(fù)執(zhí)行,這么我們來測(cè)試一下。

具體請(qǐng)求參數(shù)附上:

{
    "jobGroup": "job_group_task1_jg",
    "jobName": "job_name_task1_jn"

控制臺(tái)查驗(yàn)被暫停的task1是否被恢復(fù)執(zhí)行了,大家請(qǐng)看:

經(jīng)5min觀察,task1任務(wù)確實(shí)又重新執(zhí)行了。你也可以調(diào)用【正在執(zhí)行中的任務(wù)】接口作為輔助驗(yàn)證,不過就是要多次調(diào)用,畢竟在非執(zhí)行間隔有點(diǎn)久,畢竟task1任務(wù)間隔10s執(zhí)行一次,task2任務(wù)間隔20s執(zhí)行一次。

3.9.7 查詢正在執(zhí)行的定時(shí)任務(wù)

同上述測(cè)試步驟,我們直接通過Swagger接口文檔作為測(cè)試請(qǐng)求:

再次測(cè)試請(qǐng)求:

3.9.8 查看所有定時(shí)任務(wù)

這里我們可以查詢出所有的定時(shí)任務(wù),不區(qū)分是否正在被執(zhí)行狀態(tài)。所以始終會(huì)返回job表中的總條數(shù)。

同上述測(cè)試步驟,我們直接通過Swagger接口文檔作為測(cè)試請(qǐng)求:

3.9.9 刪除定時(shí)任務(wù)

終于寫到最后一個(gè)刪除模擬了,同上述測(cè)試步驟,我們直接通過Swagger接口文檔作為測(cè)試請(qǐng)求:

具體請(qǐng)求參數(shù)附上:

{
    "jobGroup": "job_group_task1_jg",
    "jobName": "job_name_task1_jn"
}

我們從三個(gè)地方來驗(yàn)證,分別是接口查詢所有任務(wù)數(shù),控制臺(tái)執(zhí)行打印,及數(shù)據(jù)庫job任務(wù)條數(shù)。 

重新請(qǐng)求【接口查詢所有定時(shí)任務(wù)數(shù)】截圖如下:

數(shù)據(jù)庫表qrtz_job_details中task1成功被移除了,證明task1這條定時(shí)任務(wù)確實(shí)被刪除了。

好啦,以上針對(duì)Quartz的一系列操作及測(cè)試演示了,所任何不清楚的地方都可以通過評(píng)論區(qū)或私信我,我將第一時(shí)間給予你解惑。

4. 總結(jié)

本文介紹了SpringBoot集成quartz可以使定時(shí)任務(wù)的管理變得更加方便和可靠。通過將定時(shí)任務(wù)的信息保存到數(shù)據(jù)庫中,我們可以輕松地對(duì)任務(wù)進(jìn)行增刪改查等操作。下面是一些主要的總結(jié):

配置數(shù)據(jù)源和quartz的相關(guān)屬性:需要在配置文件中指定數(shù)據(jù)源的連接信息和quartz的屬性,包括JobStore類型、表前綴、是否自動(dòng)啟動(dòng)等。

創(chuàng)建Job和Trigger:通過繼承Quartz提供的Job接口,實(shí)現(xiàn)execute方法,即可定義一個(gè)Job。同時(shí),通過指定Trigger的cron表達(dá)式或簡單的時(shí)間間隔,可以定義一個(gè)Trigger,并將其與Job綁定起來。

通過schedulerFactoryBean創(chuàng)建Scheduler:在配置類中,通過注入schedulerFactoryBean,我們可以獲取到一個(gè)Scheduler實(shí)例,然后可以通過Scheduler的API實(shí)現(xiàn)任務(wù)的管理,包括啟動(dòng)、暫停、恢復(fù)、刪除等操作。

配置JobDetail、Trigger、CronTrigger的持久化:通過將JobDetail、Trigger、CronTrigger的信息保存到數(shù)據(jù)庫中,我們可以實(shí)現(xiàn)對(duì)定時(shí)任務(wù)的持久化,即使應(yīng)用程序重新啟動(dòng)或服務(wù)器崩潰,我們也可以恢復(fù)定時(shí)任務(wù)。在配置文件中,需要指定SchedulerFactoryBean的jobStore類型為JobStoreTX,同時(shí)配置DataSourceTransactionManager和QuartzTransactionManager。

使用QuartzJobBean和JobDataMap:在Job中,可以通過繼承Quartz提供的QuartzJobBean,獲取JobExecutionContext,并從中獲取JobDataMap,通過JobDataMap可以傳遞參數(shù),實(shí)現(xiàn)Job的可配置化。

總之,通過使用SpringBoot集成quartz,我們可以方便地管理定時(shí)任務(wù),實(shí)現(xiàn)任務(wù)的持久化,同時(shí)對(duì)任務(wù)的管理變得更加靈活和可靠。 

以上就是SpringBoot集成quartz實(shí)現(xiàn)定時(shí)任務(wù)的詳細(xì)內(nèi)容,更多關(guān)于SpringBoot定時(shí)任務(wù)的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java簡單冒泡排序示例解析

    Java簡單冒泡排序示例解析

    這篇文章主要介紹了Java簡單冒泡排序示例解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • java類和對(duì)象原理與用法分析

    java類和對(duì)象原理與用法分析

    這篇文章主要介紹了java類和對(duì)象原理與用法,結(jié)合實(shí)例形式分析了java類和對(duì)象的相關(guān)概念、功能、原理、使用技巧與操作注意事項(xiàng),需要的朋友可以參考下
    2020-02-02
  • Springboot工具類StringUtils使用教程

    Springboot工具類StringUtils使用教程

    這篇文章主要介紹了Springboot內(nèi)置的工具類之StringUtils的使用,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)吧
    2022-12-12
  • SpringBoot中整合knife4j接口文檔的實(shí)踐

    SpringBoot中整合knife4j接口文檔的實(shí)踐

    這篇文章主要介紹了SpringBoot中整合knife4j接口文檔的實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Java中數(shù)學(xué)相關(guān)類的使用教程

    Java中數(shù)學(xué)相關(guān)類的使用教程

    Java是一種廣泛使用的編程語言,它提供了許多數(shù)學(xué)運(yùn)算的函數(shù)和方法,使得開發(fā)者可以輕松地進(jìn)行各種數(shù)學(xué)計(jì)算,下面這篇文章主要給大家介紹了關(guān)于Java中數(shù)學(xué)相關(guān)類使用的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • 詳解Struts2標(biāo)簽遍歷

    詳解Struts2標(biāo)簽遍歷

    這篇文章主要介紹了Struts2標(biāo)簽遍歷,以及相關(guān)的用法示例,需要的朋友可以參考下。
    2017-09-09
  • 淺談Spring @Async異步線程池用法總結(jié)

    淺談Spring @Async異步線程池用法總結(jié)

    本篇文章主要介紹了淺談Spring @Async異步線程池用法總結(jié),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-07-07
  • Java基礎(chǔ)之隱式轉(zhuǎn)換vs強(qiáng)制轉(zhuǎn)換

    Java基礎(chǔ)之隱式轉(zhuǎn)換vs強(qiáng)制轉(zhuǎn)換

    這篇文章主要介紹了Java基礎(chǔ)之隱式轉(zhuǎn)換vs強(qiáng)制轉(zhuǎn)換的相關(guān)資料,需要的朋友可以參考下
    2015-12-12
  • 一文帶你徹底剖析Java中Synchronized原理

    一文帶你徹底剖析Java中Synchronized原理

    Synchronized是Java中的隱式鎖,它的獲取鎖和釋放鎖都是隱式的,完全交由JVM幫助我們操作,在了解Synchronized關(guān)鍵字之前,首先要學(xué)習(xí)的知識(shí)點(diǎn)就是Java的對(duì)象結(jié)構(gòu),本文介紹的非常詳細(xì),需要的朋友可以參考下
    2023-05-05
  • Java中LambdaQueryWrapper的常用方法詳解

    Java中LambdaQueryWrapper的常用方法詳解

    這篇文章主要給大家介紹了關(guān)于Java中LambdaQueryWrapper常用方法的相關(guān)資料,lambdaquerywrapper是一個(gè)Java庫,用于構(gòu)建類型安全的Lambda表達(dá)式查詢,需要的朋友可以參考下
    2023-11-11

最新評(píng)論