1. 程式人生 > >spring boot + quartz定時任務框架入坑指南

spring boot + quartz定時任務框架入坑指南

quartz

Quartz是一個功能豐富的開源作業排程庫,可以整合到幾乎任何Java應用程式中

新增Maven依賴

        <!-- druid阿里巴巴資料庫連線池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.3</version>
        </dependency
>
<!-- 資料庫操作隨便你用什麼 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus</artifactId> <version>2.1.2</version> </dependency> <dependency> <groupId
>
com.baomidou</groupId> <artifactId>mybatisplus-spring-boot-starter</artifactId> <version>1.0.4</version> </dependency> <!-- quartz依賴 --> <dependency> <groupId>org.springframework</groupId
>
<artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency>

構建基本類

定時任務通用介面

import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

public interface BaseJob extends Job{
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException;
}

定時任務介面的實現類

import com.quartz.springquartz.task.BaseJob;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.JobKey;

import java.time.LocalDateTime;

public class TestJob implements BaseJob {

    public TestJob() {
    }

    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        JobDetail jobDetail = jobExecutionContext.getJobDetail();
        JobKey key = jobDetail.getKey();
        System.out.println(key.getName()+"-"+key.getGroup()+"執行時間: " + LocalDateTime.now().toString());
    }
}

quartz的JAVA config bean注入

import java.io.IOException;
import java.util.List;
import java.util.Properties;

import javax.sql.DataSource;

import org.quartz.*;
import org.quartz.ee.servlet.QuartzInitializerListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;


@Configuration
public class QuartzConfig {

    @Bean(name="SchedulerFactory")
    public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setQuartzProperties(quartzProperties());
        return factory;
    }

    /*
     * quartz初始化監聽器
     */
    @Bean
    public QuartzInitializerListener executorListener() {
        return new QuartzInitializerListener();
    }

    /*
     * 通過SchedulerFactoryBean獲取Scheduler的例項
     */
    @Bean(name="Scheduler")
    public Scheduler scheduler() throws IOException {
        return schedulerFactoryBean().getScheduler();
    }

    /**
     * 設定quartz屬性,可以從properties配置中讀取
     */
    public Properties quartzProperties() throws IOException {
        Properties prop = new Properties();
        prop.put("quartz.scheduler.instanceName", "ServerScheduler");
        prop.put("org.quartz.scheduler.instanceId", "AUTO");
        prop.put("org.quartz.scheduler.skipUpdateCheck", "true");
        prop.put("org.quartz.scheduler.instanceId", "NON_CLUSTERED");
        prop.put("org.quartz.scheduler.jobFactory.class", "org.quartz.simpl.SimpleJobFactory");
        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
        prop.put("org.quartz.threadPool.threadCount", "5");
        return prop;
    }
}

操作定時任務的service類,就不寫介面了直接實現,資料庫dao和service自己實現,Task是我定義的pojo

import com.quartz.springquartz.entity.Task;
import com.quartz.springquartz.manager.TaskService;
import com.quartz.springquartz.task.BaseJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;


@Service
public class ScheduleJobService {
    @Autowired @Qualifier("Scheduler")
    private Scheduler scheduler;

    //自己選擇所用的dao
    @Autowired
    TaskService taskService;

    public String addJob(Task task) throws Exception{
        // 啟動排程器
        scheduler.start();

        //構建job資訊
        JobDetail jobDetail = JobBuilder
                .newJob(getClass(task.getClassName()).getClass()).withIdentity(task.getName(), task.getGroup()).build();

        //表示式排程構建器(即任務執行的時間)
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(task.getCron());

        //按新的cronExpression表示式構建一個新的trigger
        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(task.getName(), task.getGroup())
                .withSchedule(scheduleBuilder).build();

        try {
            scheduler.scheduleJob(jobDetail, trigger);
            //taskService.insert(task);
        } catch (SchedulerException e) {
            e.printStackTrace();
        }
        return "success";
    }

    public JobDetail jobPause(String jobName, String jobGroupName) throws Exception
    {
        scheduler.pauseJob(JobKey.jobKey(jobName, jobGroupName));
        JobDetail detail = scheduler.getJobDetail(JobKey.jobKey(jobName, jobGroupName));
        return detail;
    }

    public void jobreschedule(String jobName, String jobGroupName, String cronExpression) throws Exception
    {
        try {
            TriggerKey triggerKey = TriggerKey.triggerKey(jobName, jobGroupName);
            // 表示式排程構建器
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            // 按新的cronExpression表示式重新構建trigger
            trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();

            // 按新的trigger重新設定job執行
            scheduler.rescheduleJob(triggerKey, trigger);
        } catch (SchedulerException e) {
            System.out.println("更新定時任務失敗"+e);
        }
    }

    public static BaseJob getClass(String classname) throws Exception
    {
        Class<?> class1 = Class.forName(classname);
        return (BaseJob)class1.newInstance();
    }
}

新增監聽器,應用啟動時,從資料庫中讀取定時任務並加入

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.quartz.springquartz.entity.Task;
import com.quartz.springquartz.manager.TaskService;
import com.quartz.springquartz.service.ScheduleJobService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;

import java.util.List;

@Configuration
public class JobListener implements ApplicationListener<ContextRefreshedEvent>{

    @Autowired
    TaskService taskService;
    @Autowired
    ScheduleJobService scheduleJobService;


    @Override
    public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent){
        EntityWrapper<Task> ew = new EntityWrapper<>();
        ew.where("status = {0}",1);
        List<Task> tasks = taskService.selectList(ew);
        System.out.println("task size = "+tasks.size());
        try {
            for (Task task : tasks) {
                scheduleJobService.addJob(task);
            }
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}

再寫一個controller測試用,就可以玩去了

import com.quartz.springquartz.entity.Task;
import com.quartz.springquartz.service.ScheduleJobService;
import com.quartz.springquartz.task.BaseJob;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import java.util.Map;


@RestController
@RequestMapping(value="/job")
public class TestController {

    //加入Qulifier註解,通過名稱注入bean
    @Autowired @Qualifier("Scheduler")
    private Scheduler scheduler;
    @Autowired
    ScheduleJobService scheduleJobService;

    @RequestMapping("/add")
    public String addJob(@RequestBody Task task) throws Exception{
        scheduleJobService.addJob(task);
        return "success";
    }

    @PostMapping(value="/pause")
    public JobKey pausejob(@RequestBody Map map) throws Exception
    {
        JobDetail detail = scheduleJobService.jobPause((String)map.get("jobName"), (String)map.get("jobGroupName"));
        return detail.getKey();
    }

    @PostMapping(value="/edit")
    public String rescheduleJob(@RequestBody Map map) throws Exception
    {
        scheduleJobService.jobreschedule((String)map.get("jobName"),(String)map.get("jobGroupName"),(String)map.get("cronExpression"));
        return "success";
    }
}

總結

最初入門,quartz配置中的儲存,分散式應用暫時沒看,下篇文章再說,只實現了單機中定時任務的資料庫持久化和動態新增