springboot 整合quartz (三):jobStores

JobStore介紹

JobStore是負責跟蹤調度器中全部的工做數據:做業任務、觸發器、日曆等。在配置文件(quartz.properties)中定義JobStore的形式,JobStore有兩種RAMJobStore和JDBCJobSTorejava

  • RAMJobStore :配置簡單,速度快,但程序中止,數據丟失
  • JDBCJobSTore :配置略微複雜,能夠保存數據

RAMJobStore

quartz.propertiesmysql

org.quartz.jobStore.class = org.quartz.simpl.RAMJobStore

OK了,不須要別的配置,直接啓動正常運行就好。git

JDBCJobStore

下載sql文件

下載地址:點擊下方的Download now github

  • sql位置:quartz解壓根目錄/docs/dbTables
  • mysql中建立test數據庫執行sql文件

配置文件

quartz.properties(這裏只給出主要配置,所有配置:參見github源碼)spring

# 持久化配置(存儲方式使用JobStoreTX,也就是數據庫)
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX

#數據庫中quartz表的表名前綴
org.quartz.jobStore.tablePrefix:qrtz_
org.quartz.jobStore.dataSource:myQuartzDB

#是否使用集羣(若是項目只部署到 一臺服務器,就不用了)
org.quartz.jobStore.isClustered = true

#============================================================================
# Configure Datasources配置數據源(可被覆蓋,若是在schedulerFactoryBean指定數據源)
#============================================================================

org.quartz.dataSource.myQuartzDB.driver:com.mysql.jdbc.Driver
org.quartz.dataSource.myQuartzDB.URL:jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
org.quartz.dataSource.myQuartzDB.user:root
org.quartz.dataSource.myQuartzDB.password:root123
org.quartz.dataSource.myQuartzDB.maxConnections:10

OK了,正常啓動運行。sql

數據庫查看

cronTrigger運行的話,數據保存部分表如下:數據庫

QRTZ_CRON_TRIGGERS:
    TRIGGER_NAME、 
    TRIGGER_GROUP、
    TRIGGER_EXPRESSION
QRTZ_JOB_DETAIL:
    JOB_NAME、
    JOB_GROUP、
    JOB_CLASS_NAME
QRTZ_TRIGGERS:
    TRIGGER_NAME、
    TRIGGER_GROUP、
    JOB_NAME、
    JOB_GROUP、
    JOB_CLASS_NAME、
    START_TIME、
    NEXT_FIRE_TIME、
    PREV_FIRE_TIM、
    MISFIRE_INSTR

注:從字段能夠看出QRTZ_TRIGGERS是一個整合表tomcat

springboot-quartz配置JDBCJobStore

pom.xmlspringboot

<!-- quartz -->
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz</artifactId>
        </dependency>
        <dependency>
            <groupId>org.quartz-scheduler</groupId>
            <artifactId>quartz-jobs</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context-support</artifactId>
            <version>5.0.7.RELEASE</version>
        </dependency>


        <!-- MySQL驅動 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>


        <!-- druid數據源驅動 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>

注:spring-context-support是spring爲了整合quartz及其餘框架的中間環境包服務器

applicatin.yml

server:
  port: 8080
  tomcat:
    uri-encoding: utf-8
spring:
  datasource:
    druid:
      # 數據庫訪問配置, 使用druid數據源 
      type: com.alibaba.druid.pool.DruidDataSource
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8
      username: root
      password: root123
    name: anhusky

quartz.properties

#============================================================================
#基礎配置
#============================================================================

# 設置調度器的實例名(instanceName) 和實例ID (instanceId)
org.quartz.scheduler.instanceName: MyScheduler
#若是使用集羣,instanceId必須惟一,設置成AUTO
org.quartz.scheduler.instanceId = AUTO

#============================================================================
#調度器線程池配置
#============================================================================

org.quartz.threadPool.class: org.quartz.simpl.SimpleThreadPool
# 指定多少個工做者線程被建立用來處理 Job
org.quartz.threadPool.threadCount: 20
# 設置工做者線程的優先級(最大值10,最小值1,經常使用值5)
org.quartz.threadPool.threadPriority: 5


#============================================================================
#Configure JobStore 做業存儲配置
#============================================================================

# 持久化配置(存儲方式使用JobStoreTX,也就是數據庫)
org.quartz.jobStore.class:org.quartz.impl.jdbcjobstore.JobStoreTX

#數據庫中quartz表的表名前綴
org.quartz.jobStore.tablePrefix:qrtz_
org.quartz.jobStore.misfireThreshold: 5000

#是否使用集羣(若是項目只部署到 一臺服務器,就不用了)
org.quartz.jobStore.isClustered = false

SchduleConfig:爲ScheduleFactoryBean配置mysql數據源

/**
 * 定時任務配置
 *
 * @author Administrator
 */
@Configuration
public class ScheduleConfig {

    @Bean
    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) throws IOException {
        SchedulerFactoryBean factory = new SchedulerFactoryBean();
        factory.setDataSource(dataSource);


        // quartz參數
        factory.setQuartzProperties(quartzProperties());

        factory.setSchedulerName("MyScheduler");
        // 延時啓動
        factory.setStartupDelay(1);
        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
        // 可選,QuartzScheduler
        // 啓動時更新己存在的Job,這樣就不用每次修改targetObject後刪除qrtz_job_details表對應記錄了
        factory.setOverwriteExistingJobs(true);
        // 設置自動啓動,默認爲true
        factory.setAutoStartup(true);


        /*
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        cronTriggerFactoryBean.setJobDetail(
                JobBuilder.newJob(ScheduleJob.class).build());
        cronTriggerFactoryBean.setStartDelay(3000);
        cronTriggerFactoryBean.setCronExpression("0/10 * * * * ?");
        // 經過這個設置 在項目啓動時啓動
        factory.setTriggers(cronTriggerFactoryBean.getObject());
        */

        return factory;
    }

    /**
     * 加載Quartz配置
     *
     * @return
     * @throws IOException
     */
    @Bean
    public Properties quartzProperties() throws IOException {
        //使用Spring的PropertiesFactoryBean對屬性配置文件進行管理
        PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
        //注意:quartz的配置文件從指定系統目錄中獲取,而不是從classpath中獲取
        propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
        //propertiesFactoryBean.setLocation(new FileSystemResource(propertiesPath));
        //重要:保證其初始化
        propertiesFactoryBean.afterPropertiesSet();
        return propertiesFactoryBean.getObject();
    }
}

JobController

@RequestMapping(value = "/job")
@Controller
public class JobController {

    @Autowired
    private Scheduler scheduler;
 ``/**
     * 添加定時任務
     */
    @PostMapping("/addJob")
    @ResponseBody
    public Map<String, String> addJob(@RequestParam(value = "jobClassName") String jobClassName,
                                      @RequestParam(value = "jobGroupName") String jobGroupName,
                                      @RequestParam(value = "cronExpression") String cronExpression) {
        Map<String, String> returnData = new HashMap<>();
        try {

            JobDetail jobDetail = JobBuilder
                    .newJob(getClass(jobClassName).getClass())
                    .withIdentity("測試-1-jojobdetailbdetail")
                    .build();

            //構建CronTrigger觸發器
            CronTrigger cronTrigger = TriggerBuilder
                    .newTrigger()
                    .withSchedule(cronSchedule(cronExpression)
                           .withMisfireHandlingInstructionDoNothing()
                    )
                    .withIdentity("測試-1-cronTrigger")
                    .build();

            //註冊調度任務
            scheduler.scheduleJob(jobDetail, cronTrigger);
            //啓動任務
            scheduler.start();

            returnData.put("msg", "添加調度任務成功");
        } catch (Exception e) {
            returnData.put("msg", "添加調度任務異常:" + e.getMessage());
        }
        return returnData;
    }
    /**
     * 暫停定時任務
     *
     * @param jobClassName
     * @param jobGroupName
     * @return
     */
    @PutMapping(value = "/pauseJob")
    @ResponseBody
    public Map<String, String> pauseJob(@RequestParam(value = "jobClassName") String jobClassName,
                                        @RequestParam(value = "jobGroupName") String jobGroupName) {
        Map<String, String> returnData = new HashMap<String, String>();
        try {
            //JobKey定義了job的名稱和組別
            JobKey jobKey = JobKey.jobKey(jobClassName, jobGroupName);
            //暫停任務
            scheduler.pauseJob(jobKey);

            returnData.put("msg", "暫停調度任務成功");
        } catch (SchedulerException e) {
            returnData.put("msg", "暫停調度任務異常:" + e.getMessage());
        } catch (Exception e) {
            returnData.put("msg", "暫停調度任務異常:" + e.getMessage());
        }

        return returnData;
    }

    /**
     * 啓動已經暫停的任務
     *
     * @param jobClassName
     * @param jobGroupName
     * @return
     */
    @PutMapping(value = "/resumeJob")
    @ResponseBody
    public Map<String, String> resumeJob(String jobClassName,
                                         String jobGroupName) {
        Map<String, String> returnData = new HashMap<String, String>();
        try {
            //JobKey定義了job的名稱和組別
            JobKey jobKey = JobKey.jobKey(jobClassName, jobGroupName);
            //繼續任務
            scheduler.resumeJob(jobKey);
            returnData.put("msg", "繼續調度任務成功");
        } catch (SchedulerException e) {
            returnData.put("msg", "繼續調度任務異常:" + e.getMessage());
        } catch (Exception e) {
            returnData.put("msg", "繼續調度任務異常:" + e.getMessage());
        }

        return returnData;
    }

    /**
     * 更新定時任務:
     * --傳入的triggerKey有與之匹配的
     * --舊觸發器的觸發時間沒有完成
     *
     * @param jobClassName
     * @param jobGroupName
     * @param cronExpression
     * @return
     */
    @PutMapping(value = "/rescheduleJob")
    @ResponseBody
    public Map<String, String> rescheduleJob(String jobClassName,
                                             String jobGroupName,
                                             String cronExpression) {
        Map<String, String> returnData = new HashMap<String, String>();
        try {

            //構建舊的TriggerKey
            TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);

            //經過cron表達式構建CronScheduleBuilder
            CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);

            //從調度容器中獲取舊的CronTrigger
            CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);

            //更新CronTrigger
            trigger = trigger.getTriggerBuilder()
                    .withIdentity(triggerKey)
                    //工做項1:job名以及所屬組
                    .withSchedule(scheduleBuilder)
                    //工做項2:指定調度參數
                    .build();//構建

            //更新調度任務
            scheduler.rescheduleJob(triggerKey, trigger);

            returnData.put("msg", "更新調度任務成功");
        } catch (Exception e) {
            returnData.put("msg", "更新調度任務異常:" + e.getMessage());
        }

        return returnData;
    }


    /**
     * @param jobClassName
     * @param jobGroupName
     * @return
     */
    @DeleteMapping(value = "/removeJob")
    @ResponseBody
    public Map<String, String> removeJob(String jobClassName,
                                         String jobGroupName) {
        Map<String, String> returnData = new HashMap<String, String>();
        try {
            //得到調度容器
            //Scheduler scheduler = getCurrentScheduler();
            //TriggerKey定義了trigger的名稱和組別
            TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);

            //暫停觸發器
            scheduler.resumeTrigger(triggerKey);
            //暫停觸發器
            scheduler.unscheduleJob(triggerKey);
            //移除任務
            scheduler.deleteJob(JobKey.jobKey(jobClassName, jobGroupName));

            returnData.put("msg", "刪除調度任務成功");
        } catch (SchedulerException e) {
            returnData.put("msg", "刪除調度任務異常:" + e.getMessage());
        } catch (Exception e) {
            returnData.put("msg", "刪除調度任務異常:" + e.getMessage());
        }

        return returnData;
    }


    /**
     * 得到指定的類實例
     *
     * @param classname
     * @return
     * @throws ServerException
     */
    private Job getClass(String classname) throws ServerException {
        Job baseJob = null;
        try {
            //加載參數指定的類
            Class<?> classTmp = Class.forName(classname);
            //實例化
            baseJob = (Job) classTmp.newInstance();
        } catch (Exception e) {
            System.out.println(classname + "......找不到相應的類");
        }

        return baseJob;
    }
}

源碼地址:

github地址

相關文章
相關標籤/搜索