1. 程式人生 > >Spring Boot2.x 整合quartz叢集

Spring Boot2.x 整合quartz叢集

springboot2.x支援對quartz的自動配置,引入jar

		<!-- spring boot2.x + quartz -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-quartz</artifactId>
		</dependency>

資料庫建表

    到官網上下載最新quartz版本,在docs\dbTables檔案目錄下找到建表sql指令碼

quartz叢集相關配置

springboot會讀取yml檔案內容並將值組裝到QuartzProperties類中

spring:
  quartz:
    job-store-type: jdbc #資料庫方式
    jdbc:
      initialize-schema: never #不初始化表結構
    properties:
      org:
        quartz:
          scheduler:
            instanceId: AUTO #預設主機名和時間戳生成例項ID,可以是任何字串,但對於所有排程程式來說,必須是唯一的 對應qrtz_scheduler_state INSTANCE_NAME欄位
            #instanceName: clusteredScheduler #quartzScheduler
          jobStore:
            class: org.quartz.impl.jdbcjobstore.JobStoreTX #持久化配置
            driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate #我們僅為資料庫製作了特定於資料庫的代理
            useProperties: true #以指示JDBCJobStore將JobDataMaps中的所有值都作為字串,因此可以作為名稱 - 值對儲存而不是在BLOB列中以其序列化形式儲存更多複雜的物件。從長遠來看,這是更安全的,因為您避免了將非String類序列化為BLOB的類版本問題。
            tablePrefix: qrtz_  #資料庫表字首
            misfireThreshold: 60000 #在被認為“失火”之前,排程程式將“容忍”一個Triggers將其下一個啟動時間通過的毫秒數。預設值(如果您在配置中未輸入此屬性)為60000(60秒)。
            clusterCheckinInterval: 5000 #設定此例項“檢入”*與群集的其他例項的頻率(以毫秒為單位)。影響檢測失敗例項的速度。
            isClustered: true #開啟群集功能
          threadPool: #連線池
            class: org.quartz.simpl.SimpleThreadPool
            threadCount: 10
            threadPriority: 5
            threadsInheritContextClassLoaderOfInitializingThread: true

注意:本文版本2.0.4,隨著版本迭代。屬性引數會有變化。如下為2.1.0版本官網文件說明

# QUARTZ SCHEDULER (QuartzProperties)
spring.quartz.auto-startup=true # Whether to automatically start the scheduler after initialization.
spring.quartz.jdbc.comment-prefix=-- # Prefix for single-line comments in SQL initialization scripts.
spring.quartz.jdbc.initialize-schema=embedded # Database schema initialization mode.
spring.quartz.jdbc.schema=classpath:org/quartz/impl/jdbcjobstore/
[email protected]
@[email protected]@.sql # Path to the SQL file to use to initialize the database schema. spring.quartz.job-store-type=memory # Quartz job store type. spring.quartz.overwrite-existing-jobs=false # Whether configured jobs should overwrite existing job definitions. spring.quartz.properties.*= # Additional Quartz Scheduler properties. spring.quartz.scheduler-name=quartzScheduler # Name of the scheduler. spring.quartz.startup-delay=0s # Delay after which the scheduler is started once initialization completes. spring.quartz.wait-for-jobs-to-complete-on-shutdown=false # Whether to wait for running jobs to complete on shutdown.

擴充套件SchedulerFactoryBean

SpringBoot的QuartzAutoConfiguration類會幫我自動配置SchedulerFactoryBean。使用SpringBoot提供的SchedulerFactoryBeanCustomizer介面去擴充套件SchedulerFactoryBean。

@Component
public class MySchedulerFactoryBean implements SchedulerFactoryBeanCustomizer {
    @Override
    public void customize(SchedulerFactoryBean schedulerFactoryBean) {
        schedulerFactoryBean.setOverwriteExistingJobs(true);//更新trigger的 表示式時,同步資料到資料庫qrtz_cron_triggers表 開啟
        schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");//注入applicationContext
        //to do 

    }
}

定義JobDetail和Trigger

springboot自動把Trigger注入schedulerFactoryBean中

@Configuration
public class QuartzConfig {


    /**
     * 定義JobDetail 直接使用 jobDetailFactoryBean.getObject 獲得的是空
     * @return
     */
    @Bean
    public JobDetailFactoryBean printTimeJobDetail(){
        JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
        // durability 表示任務完成之後是否依然保留到資料庫,預設falses
        jobDetailFactoryBean.setDurability(true);
        //當Quartz服務被中止後,再次啟動或叢集中其他機器接手任務時會嘗試恢復執行之前未完成的所有任務
        jobDetailFactoryBean.setRequestsRecovery(true);
        jobDetailFactoryBean.setJobClass(MyDetailQuartzJobBean.class);
        jobDetailFactoryBean.setDescription("列印時間定時器2");
        Map<String,String> jobDataAsMap = new HashMap<>();
        jobDataAsMap.put("targetObject","printTimeQuartz"); //spring 中bean的名字
        jobDataAsMap.put("targetMethod","execute");   //執行方法名
        jobDetailFactoryBean.setJobDataAsMap(jobDataAsMap);
        return  jobDetailFactoryBean;
    }

    /**
     * 定義一個Trigger
     * @return
     */
    @Bean
    public CronTriggerFactoryBean printTimeCronTrigger(JobDetail printTimeJobDetail){
        CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
        // 設定jobDetail
        cronTriggerFactoryBean.setJobDetail(printTimeJobDetail);
        //秒 分 小時 日 月 星期 年  每10分鐘
        cronTriggerFactoryBean.setCronExpression("0 0/10 * * * ?");
        //trigger超時處理策略 預設1:總是會執行頭一次 2:不處理
        cronTriggerFactoryBean.setMisfireInstruction(2);
        return  cronTriggerFactoryBean;
    }


}

JobClass

public class MyDetailQuartzJobBean extends QuartzJobBean {
    private Logger logger = LoggerFactory.getLogger(MyDetailQuartzJobBean.class);
    /**
     * 目標物件
     */
    private String targetObject;
    /**
     * 執行的方法
     */
    private String targetMethod;
    /**
     * spring 上下文物件
     */
    private ApplicationContext ctx;

    @Override
    protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
        try {
            logger.info("execute [" + targetObject + "] at once>>>>>>");
            Object otargetObject = ctx.getBean(targetObject);
            Method m = otargetObject.getClass().getMethod(targetMethod, new Class[] {});
            m.invoke(otargetObject, new Object[]{});
        } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    public void setApplicationContext(ApplicationContext applicationContext) {
        this.ctx = applicationContext;
    }

    public void setTargetObject(String targetObject) {
        this.targetObject = targetObject;
    }

    public void setTargetMethod(String targetMethod) {
        this.targetMethod = targetMethod;
    }
}