springboot quartz 手寫任務調度

添加引用

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

QuartzFactory類:主要用於解決springboot quartz  job 無法注入bean的問題。

package com.example.springboot;

import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;

@Component
public class QuartzFactory extends AdaptableJobFactory {

    /**
     * AutowireCapableBeanFactory接口是BeanFactory的子類
     * 可以連接和填充那些生命週期不被Spring管理的已存在的bean實例
     */
    private AutowireCapableBeanFactory factory;

    public QuartzFactory(AutowireCapableBeanFactory factory) {
        this.factory = factory;
    }

    /**
     * 創建Job實例
     */
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        // 實例化對象
        Object job = super.createJobInstance(bundle);
        // 進行注入(Spring管理該Bean        factory.autowireBean(job);
        //返回對象
        return job;
    }

}

 

QuartzConfig類:主要用於解決springboot quartz  job 無法注入bean的問題,需要配合QuartzFactory類。

package com.example.springboot;

import org.quartz.Scheduler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;

@Configuration
public class QuartzConfig {

    private QuartzFactory quartzFactory;

    public QuartzConfig(QuartzFactory quartzFactory) {
        this.quartzFactory = quartzFactory;
    }

    /**
     * 配置SchedulerFactoryBean
     * 將一個方法產生爲Bean並交給Spring容器管理
     */
    @Bean
    public SchedulerFactoryBean schedulerFactoryBean() {
        // Spring提供SchedulerFactoryBeanScheduler提供配置信息,並被Spring容器管理其生命週期
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        // 設置自定義Job Factory,用於Spring管理Job bean
        factory.setJobFactory(quartzFactory);
        return factory;
    }

    @Bean(name = "scheduler")
    public Scheduler scheduler() {
        return schedulerFactoryBean().getScheduler();
    }

}

 

QuartzService類:封裝一些任務調度的東西,主要也用於測試注入job的bean對象。

package com.example.springboot;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.Date;

@Slf4j
@Service
public class QuartzService {

    @Autowired
    private Scheduler scheduler;

    // 添加調度任務
    public Boolean addScheduler(Integer id, String cron) throws Exception {
        // 判斷,如果因爲意外將過期調度任務傳遞過來,進行排除
        // ...

        // 添加一個去重複的操作
        if (scheduler.getJobDetail(JobKey.jobKey(id.toString())) != null) {
            return Boolean.TRUE;
        }

        // 構建一個job
        JobDetail jobDetail = JobBuilder
                .newJob(QuartzJob.class)
                .withIdentity(id.toString())
                .usingJobData("param", id.toString())
                .build();

        // 構建一個trigger
        CronTrigger trigger = TriggerBuilder.newTrigger()
                .withIdentity(id.toString())
                .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                .build();

        // 構建一個scheduler
        Date nextExecuteTime = scheduler.scheduleJob(jobDetail, trigger);
        //開始執行
        scheduler.start();
        return Boolean.TRUE;
    }

    // 取消調度任務,並且清除緩存
    public Boolean deleteJob(Integer id) {
        Boolean result = Boolean.FALSE;
        try {
            // 刪除job
            result = scheduler.deleteJob(JobKey.jobKey(id.toString()));
        } catch (Exception ex) {
            // 記錄個日誌
            log.error(String.format("%s-刪除調度器出現異常:%s,堆棧信息:%s", id, ex.getMessage(), ExceptionUtils.getStackTrace(ex)));
        }
        return result;
    }

    // 查詢調度任務
    public Boolean query(Integer id) throws Exception {
        JobDetail jobDetail = scheduler.getJobDetail(JobKey.jobKey(id.toString()));
        if (jobDetail == null) {
            return Boolean.FALSE;
        } else {
            return Boolean.TRUE;
        }
    }

    // 得到cron的下一次執行時間
    public String getNextExecuteTime(String cron) {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // 驗證cron的正確性
        System.out.println(CronExpression.isValidExpression(cron));
        if (CronExpression.isValidExpression(cron)) {
            CronTrigger trigger = TriggerBuilder.newTrigger()
                    .withIdentity("default")
                    .withSchedule(CronScheduleBuilder.cronSchedule(cron))
                    .build();
            // 獲取到下一次執行時間
            Date nextTime = trigger.getFireTimeAfter(trigger.getStartTime());
            return df.format(nextTime);
        } else {
            return "表達式不合法";
        }
    }

}

 

QuartzJob類:就是job要執行的類,該類如果不做特殊處理,是無法將bean對象注入該類的。重點就是QuartzFactory和QuartzConfig兩個類的添加,沒有什麼需要特別注意的東西。

package com.example.springboot;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

@Slf4j
@Component
public class QuartzJob implements Job {

    // 正常情況下,這裏是注入不進來的,故意寫個來檢驗注入bean問題
    @Autowired
    private QuartzService quartzService;

    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        try {
            JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
            // 獲取參數
            String param = jobDataMap.getString("param");
            System.out.println(param + "——開始執行");
            Thread.sleep(1000);
            // 調用刪除調度器的方法
            Boolean result = quartzService.deleteJob(Integer.valueOf(param));
            System.out.println(param + "——執行結束,取消調度任務結果:" + result);
        } catch (Exception ex) {
            log.error(String.format("執行調度器出現異常:%s,堆棧信息:%s", ex.getMessage(), ExceptionUtils.getStackTrace(ex)));
        }

    }
}

 

QuartzController類:測試類,用於調用任務的添加,刪除和查詢。

package com.example.springboot;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;


@Slf4j
@RestController
public class QuartzController {

    @Autowired
    private QuartzService quartzService;

    @RequestMapping("/quartz/add/{id}")
    private Boolean index(@PathVariable Integer id, @RequestBody String cron) throws Exception {
        Boolean result = quartzService.addScheduler(id, cron);
        return result;
    }

    @RequestMapping("/quartz/delete/{id}")
    public Boolean cancel(@PathVariable Integer id) {
        Boolean result = quartzService.deleteJob(id);
        return result;
    }

    @RequestMapping("/quartz/query/{id}")
    public Boolean query(@PathVariable Integer id) throws Exception {
        Boolean result = quartzService.query(id);
        return result;
    }

}

 

注意:由於job類無法注入spring bean對象,因此需要添加QuartzFactory和QuartzConfig兩個類,然後Scheduler調用方式,不是採用new,而是注入的方式,參見QuartzService中的Scheduler使用

 

CronExpression cronExpression = new CronExpression("30 30 17 * * ? ");
//這個方法沒有實現
System.out.println("getFinalFireTime - " + cronExpression.getFinalFireTime());
//得到給定時間下一個無效的時間
System.out.println("GetNextInvalidTimeAfter - " + cronExpression.getNextInvalidTimeAfter(new Date()));
//得到給定時間的下一個有效的時間
System.out.println("GetNextValidTimeAfter - " + cronExpression.getNextValidTimeAfter(new Date()));
//得到給定時間下一個符合表達式的時間
System.out.println("GetTimeAfter - " + cronExpression.getTimeAfter(new Date()));
//這個方法沒有實現
System.out.println("GetTimeBefore - " + cronExpression.getTimeBefore(new Date()));
//給定時間是否符合表達式
System.out.println("IsSatisfiedBy - " + cronExpression.isSatisfiedBy(new Date()));

 

吐槽一下,網上代碼都是各種copy,找點有用的找不到。就想找爲什麼job類無法注入,解決方案都找半天沒有用,後來自己總結搞了下,其實就是添加兩個類就可以了,很簡單,非得貼一大坨代碼,也沒有說明解釋。springboot quartz無法注入問題參見上述紅字把。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章