跳到主要內容

Java Quartz2.2 入門

Quartz

Quartz 是一個功能滿完整的 Java Schedule 排程工具, 核心就圍繞在 Scheduler 與 Job 的操作上。

  • Scheduler - the main API for interacting with the scheduler.
  • Job - an interface to be implemented by components that you wish to have executed by the scheduler.
  • JobDetail - used to define instances of Jobs.
  • Trigger - a component that defines the schedule upon which a given Job will be executed.
  • JobBuilder - used to define/build JobDetail instances, which define instances of Jobs.
  • TriggerBuilder - used to define/build Trigger instances.


Job

Quartz 的 Job 被定義為需要 implement org.quartz.Job,
需要實作 void execute(JobExecutionContext jobExecutionContext),
jobExecutionContext, 可以取得 Job 的 Scheduler, Trigger, JobDetail 的相關設定, 相關的說明可以參考 tutorial-lesson-02.


import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;

/**
 * Created by jerry on 2017/11/17.
 */
public class HelloJob implements Job {

    /**
     * Quartz Job 要求要一個 empty constructor,
     * 讓 Scheduler 來 instantiate
     */
    public HelloJob() {
    }

    /**
     * Quartz Job 要執行的動作
     *
     * @param jobExecutionContext
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
        ObjectMapper objectMapper = new ObjectMapper();
        JobDetail jobInstant = jobExecutionContext.getJobDetail();
        System.out.println("===========================================");
        System.out.println("Description: " + jobInstant.getDescription());
        System.out.println("Job Key: " + jobInstant.getKey());
        System.out.println("is Concurrent Execution Disallowed: " + jobInstant.isConcurrentExectionDisallowed());
        System.out.println("is Durable: " + jobInstant.isDurable());
        System.out.println("requests Recovery: " + jobInstant.requestsRecovery());

        System.out.println("===========================================");
        JobDataMap jobData = jobInstant.getJobDataMap();

        try {
            String jobDataJson = objectMapper.writeValueAsString(jobData);
            System.out.println("Job Data Map Data: " + jobDataJson);

        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }

    }
}


Scheduler

定義完 Job 之後, 要觸發還需要 Scheduler, Scheduler 可以用來分配 Job 與 Trigger,
藉由 SchedulerFactory 來取得 instance, SchedulerFactory 會載入 quartz.properties 定義的相關設定(參考


import static org.quartz.DateBuilder.evenMinuteDate;
import static org.quartz.JobBuilder.newJob;
import static org.quartz.TriggerBuilder.newTrigger;

import com.google.common.collect.ImmutableMap;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SchedulerFactory;
import org.quartz.Trigger;
import org.quartz.impl.StdSchedulerFactory;

import java.util.Date;

/**
 * Created by jerry on 2017/11/17.
 */
public class HelloWorldSchedule {
    
    public void run() throws SchedulerException, InterruptedException {
        // init job
        JobDetail job = newJob(HelloJob.class)
            .withDescription("quartz job - hello world")
            .withIdentity("job-name", "job-group")
            .usingJobData("string-key", "value1")
            .usingJobData("long-key", 1L)
            .usingJobData(new JobDataMap(
                ImmutableMap.builder().put("map-key", "map-value").build()))
            .build();

        // set trigger time
        Date runTime = evenMinuteDate(new Date());

        // init trigger, start at next even minute time
        Trigger trigger = newTrigger()
            .withIdentity("trigger-name", "trigger-group")
            .startAt(runTime)
            .build();

        // init schedule
        SchedulerFactory schedulerFactory = new StdSchedulerFactory();
        Scheduler scheduler = schedulerFactory.getScheduler();
        scheduler.scheduleJob(job, trigger);

        // start up schedule
        scheduler.start();

        // sleep 10 seconds, make sure the scheduler be triggered
        Thread.sleep(60L * 1000);

        scheduler.shutdown(true);
    }
}

Run Scheduler


@Test
public void testScheduler() throws SchedulerException, InterruptedException {
    HelloWorldSchedule helloWorldSchedule = new HelloWorldSchedule();
    helloWorldSchedule.run();
}

留言

這個網誌中的熱門文章

Parse URI query string to Key Value

Parse URI query String to Map 做 urlDecode 處理 沒有任何 query String 回傳 Empty Map 確保只處理 key-value 結構的 query String package com.example.util; import lombok.extern.slf4j.Slf4j; import org.apache.http.client.utils.URIBuilder; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLDecoder; import java.util.LinkedHashMap; import java.util.Map; import java.util.Objects; /** * Created by jerry on 2017/12/28. * * @author jerry */ @Slf4j public class UriUtil { private UriUtil() { } public static Map splitQuery(final String uri) { Map queryPairs = new LinkedHashMap (); try { final URI uri = new URIBuilder(uri).build(); final String rawQuery = uri.getRawQuery(); log.info("CurrentUrl Query: {}", rawQuery); // 過濾沒有 query string // 還有過濾無法成對 keyValue 的 query, e.g. http://host/path?123 if (Objects.isNull(rawQuery) |...

Spring-boot Thymeleaf Html5 SAXParseException 解析錯誤

thymeleaf 解析 html5 出錯 <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> <meta name="description" content=""> <meta name="author" content=""> <title>SB Admin - Start Bootstrap Template</title> <!-- Bootstrap core CSS--> <link href="../static/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet"> <!-- Custom fonts for this template--> <link href="../static/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css"> <!-- Page level plugin CSS--> <link href="../static/vendor/datatables/dataTables.bootstrap4.css" rel="stylesheet"> <!-- Custom styles for this template--> <li...

Google Compute Engine‎ - AccessDeniedExceptions 403

原因 打算從 instance 打包 logs 到 google cloud storage 發生了 AccessDeniedException: 403 Insufficient OAuth2 scope to perform this operation. , 看起來是 instance 沒有 storage 權限 解決 Reference: https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances#changeserviceaccountandscopes 重新設定 service account 權限 instance 上內建有 gcloud , 就直接用現有的工具查詢一下 instance 的 account. $ gsutil info 或者在本機直接 gcloud compute instances describe INSTANCE_NAMES Account: [alpha-number-compute@developer.gserviceaccount.com] Project: [our-project-name] 會看到 instance 的一些狀態, 接下來就簡單多了, 按照下列的說明, 要先 stop instance, 更改 storage scope 再重新 start 。 To change an instance's service account and access scopes, the instance must be temporarily stopped. To stop your instance, read the documentation for Stopping an instance. After changing the service account or access scopes, remember to restart the instance. # Stop Instance gcloud compute instances stop INSTANCE_NAMES # 設定 storage scope 為 full (Read, Write) gcloud co...