SpringBoot分散式定時器
阿新 • • 發佈:2020-07-10
需求背景
專案需要對接大資料平臺,定時更新相關的統計資料
version
SpringBoot: 2.2.4.RELEASE
MySQL: 5.5.4
Quartz: 2.3.0
實現
匯入資料庫表
因為Quartz 叢集依賴於資料庫,所以必須首先建立Quartz資料庫表。Quartz 包括了所有被支援的資料庫平臺的 SQL 指令碼
-- ---------------------------- -- Table structure for QRTZ_BLOB_TRIGGERS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_BLOB_TRIGGERS`; CREATE TABLE `QRTZ_BLOB_TRIGGERS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `BLOB_DATA` blob NULL, PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, INDEX `SCHED_NAME`(`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, CONSTRAINT `QRTZ_BLOB_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_CALENDARS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_CALENDARS`; CREATE TABLE `QRTZ_CALENDARS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `CALENDAR_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `CALENDAR` blob NOT NULL, PRIMARY KEY (`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_CRON_TRIGGERS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_CRON_TRIGGERS`; CREATE TABLE `QRTZ_CRON_TRIGGERS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `CRON_EXPRESSION` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TIME_ZONE_ID` varchar(80) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, CONSTRAINT `QRTZ_CRON_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_FIRED_TRIGGERS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_FIRED_TRIGGERS`; CREATE TABLE `QRTZ_FIRED_TRIGGERS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `ENTRY_ID` varchar(95) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `INSTANCE_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `FIRED_TIME` bigint(13) NOT NULL, `SCHED_TIME` bigint(13) NOT NULL, `PRIORITY` int(11) NOT NULL, `STATE` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `JOB_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `JOB_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`SCHED_NAME`, `ENTRY_ID`) USING BTREE, INDEX `IDX_QRTZ_FT_TRIG_INST_NAME`(`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE, INDEX `IDX_QRTZ_FT_INST_JOB_REQ_RCVRY`(`SCHED_NAME`, `INSTANCE_NAME`, `REQUESTS_RECOVERY`) USING BTREE, INDEX `IDX_QRTZ_FT_J_G`(`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE, INDEX `IDX_QRTZ_FT_JG`(`SCHED_NAME`, `JOB_GROUP`) USING BTREE, INDEX `IDX_QRTZ_FT_T_G`(`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, INDEX `IDX_QRTZ_FT_TG`(`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_JOB_DETAILS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_JOB_DETAILS`; CREATE TABLE `QRTZ_JOB_DETAILS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `JOB_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `JOB_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `DESCRIPTION` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `JOB_CLASS_NAME` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `IS_DURABLE` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `IS_NONCONCURRENT` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `IS_UPDATE_DATA` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `REQUESTS_RECOVERY` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `JOB_DATA` blob NULL, PRIMARY KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE, INDEX `IDX_QRTZ_J_REQ_RECOVERY`(`SCHED_NAME`, `REQUESTS_RECOVERY`) USING BTREE, INDEX `IDX_QRTZ_J_GRP`(`SCHED_NAME`, `JOB_GROUP`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_LOCKS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_LOCKS`; CREATE TABLE `QRTZ_LOCKS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `LOCK_NAME` varchar(40) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`SCHED_NAME`, `LOCK_NAME`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_PAUSED_TRIGGER_GRPS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_PAUSED_TRIGGER_GRPS`; CREATE TABLE `QRTZ_PAUSED_TRIGGER_GRPS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, PRIMARY KEY (`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_SCHEDULER_STATE -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_SCHEDULER_STATE`; CREATE TABLE `QRTZ_SCHEDULER_STATE` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `INSTANCE_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `LAST_CHECKIN_TIME` bigint(13) NOT NULL, `CHECKIN_INTERVAL` bigint(13) NOT NULL, PRIMARY KEY (`SCHED_NAME`, `INSTANCE_NAME`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_SIMPLE_TRIGGERS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_SIMPLE_TRIGGERS`; CREATE TABLE `QRTZ_SIMPLE_TRIGGERS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `REPEAT_COUNT` bigint(7) NOT NULL, `REPEAT_INTERVAL` bigint(12) NOT NULL, `TIMES_TRIGGERED` bigint(10) NOT NULL, PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, CONSTRAINT `QRTZ_SIMPLE_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_SIMPROP_TRIGGERS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_SIMPROP_TRIGGERS`; CREATE TABLE `QRTZ_SIMPROP_TRIGGERS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `STR_PROP_1` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `STR_PROP_2` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `STR_PROP_3` varchar(512) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `INT_PROP_1` int(11) NULL DEFAULT NULL, `INT_PROP_2` int(11) NULL DEFAULT NULL, `LONG_PROP_1` bigint(20) NULL DEFAULT NULL, `LONG_PROP_2` bigint(20) NULL DEFAULT NULL, `DEC_PROP_1` decimal(13, 4) NULL DEFAULT NULL, `DEC_PROP_2` decimal(13, 4) NULL DEFAULT NULL, `BOOL_PROP_1` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `BOOL_PROP_2` varchar(1) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, CONSTRAINT `QRTZ_SIMPROP_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) REFERENCES `QRTZ_TRIGGERS` (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic; -- ---------------------------- -- Table structure for QRTZ_TRIGGERS -- ---------------------------- DROP TABLE IF EXISTS `QRTZ_TRIGGERS`; CREATE TABLE `QRTZ_TRIGGERS` ( `SCHED_NAME` varchar(120) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `JOB_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `JOB_GROUP` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `DESCRIPTION` varchar(250) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `NEXT_FIRE_TIME` bigint(13) NULL DEFAULT NULL, `PREV_FIRE_TIME` bigint(13) NULL DEFAULT NULL, `PRIORITY` int(11) NULL DEFAULT NULL, `TRIGGER_STATE` varchar(16) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `TRIGGER_TYPE` varchar(8) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, `START_TIME` bigint(13) NOT NULL, `END_TIME` bigint(13) NULL DEFAULT NULL, `CALENDAR_NAME` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `MISFIRE_INSTR` smallint(2) NULL DEFAULT NULL, `JOB_DATA` blob NULL, PRIMARY KEY (`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`) USING BTREE, INDEX `IDX_QRTZ_T_J`(`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) USING BTREE, INDEX `IDX_QRTZ_T_JG`(`SCHED_NAME`, `JOB_GROUP`) USING BTREE, INDEX `IDX_QRTZ_T_C`(`SCHED_NAME`, `CALENDAR_NAME`) USING BTREE, INDEX `IDX_QRTZ_T_G`(`SCHED_NAME`, `TRIGGER_GROUP`) USING BTREE, INDEX `IDX_QRTZ_T_STATE`(`SCHED_NAME`, `TRIGGER_STATE`) USING BTREE, INDEX `IDX_QRTZ_T_N_STATE`(`SCHED_NAME`, `TRIGGER_NAME`, `TRIGGER_GROUP`, `TRIGGER_STATE`) USING BTREE, INDEX `IDX_QRTZ_T_N_G_STATE`(`SCHED_NAME`, `TRIGGER_GROUP`, `TRIGGER_STATE`) USING BTREE, INDEX `IDX_QRTZ_T_NEXT_FIRE_TIME`(`SCHED_NAME`, `NEXT_FIRE_TIME`) USING BTREE, INDEX `IDX_QRTZ_T_NFT_ST`(`SCHED_NAME`, `TRIGGER_STATE`, `NEXT_FIRE_TIME`) USING BTREE, INDEX `IDX_QRTZ_T_NFT_MISFIRE`(`SCHED_NAME`, `MISFIRE_INSTR`, `NEXT_FIRE_TIME`) USING BTREE, INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE`(`SCHED_NAME`, `MISFIRE_INSTR`, `NEXT_FIRE_TIME`, `TRIGGER_STATE`) USING BTREE, INDEX `IDX_QRTZ_T_NFT_ST_MISFIRE_GRP`(`SCHED_NAME`, `MISFIRE_INSTR`, `NEXT_FIRE_TIME`, `TRIGGER_GROUP`, `TRIGGER_STATE`) USING BTREE, CONSTRAINT `QRTZ_TRIGGERS_ibfk_1` FOREIGN KEY (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) REFERENCES `QRTZ_JOB_DETAILS` (`SCHED_NAME`, `JOB_NAME`, `JOB_GROUP`) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
引入pom依賴
<!--Spring Boot 整合 Quartz 實現定時任務 --> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.3.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>5.2.5.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.21</version> </dependency>
引入quartz.properties配置
這裡要注意,使用分散式叢集跑定時,需要使用到db持久化,所以需要所有的節點共享一個數據源.
#============================================================================ # Configure JobStore # Using Spring datasource in SchedulerConfig.java # Spring uses LocalDataSourceJobStore extension of JobStoreCMT #============================================================================ org.quartz.jobStore.useProperties=false #表名的字首 org.quartz.jobStore.tablePrefix = QRTZ_ #isClustered 屬性為 true,你就告訴了 Scheduler 例項要它參與到一個叢集當中 org.quartz.jobStore.isClustered = true #clusterCheckinInterval 屬性定義了Scheduler 例項檢入到資料庫中的頻率(單位:毫秒),預設值是 15000 org.quartz.jobStore.clusterCheckinInterval = 3000 org.quartz.jobStore.misfireThreshold = 60000 org.quartz.jobStore.txIsolationLevelReadCommitted = true #class屬性為 JobStoreTX,將任務持久化到資料中。quartz依賴於資料庫查詢任務狀態 org.quartz.jobStore.class = org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate #============================================================================ # Configure Main Scheduler Properties # Needed to manage cluster instances #============================================================================ #instanceName屬性可為任何值,用在 JDBC JobStore 中來唯一標識例項,但是所有叢集節點中必須相同。 org.quartz.scheduler.instanceName = ClusterQuartz #instanceId 屬性為 AUTO即可,基於主機名和時間戳來產生例項 ID org.quartz.scheduler.instanceId= AUTO org.quartz.scheduler.rmi.export = false org.quartz.scheduler.rmi.proxy = false org.quartz.scheduler.wrapJobExecutionInUserTransaction = false #============================================================================ # Configure ThreadPool # Can also be configured in spring configuration # 此處使用的java的執行緒池 #============================================================================ #org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool #org.quartz.threadPool.threadCount = 5 #org.quartz.threadPool.threadPriority = 5 #org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
自定義JobFactory
package com.zkml.reception.config;
import org.quartz.spi.TriggerFiredBundle;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.scheduling.quartz.AdaptableJobFactory;
import org.springframework.stereotype.Component;
/**
* @Author: Luzy
* @Date: 2020-07-06 11:06
* @Description: 自定義jobFactory
*/
@Component
public class SpringJobFactory extends AdaptableJobFactory {
@Autowired
private AutowireCapableBeanFactory capableBeanFactory;
@Override
protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
Object jobInstance = super.createJobInstance(bundle);
capableBeanFactory.autowireBean(jobInstance);
return jobInstance;
}
}
說明:
若不自定義jobFactory, 後面在定時任務的job中進行屬性注入的時候就會發現所有的物件都無法使用Autowired進行注入,會有空指標異常丟擲
原因
Quartz初始化是自己的JobContext,不同於Spring的ApplicationContext,所以無法直接注入,導致使用時產生空指標異常!
版本也有關係: spring3.1以下的版本必須使用quartz1.x系列,3.1以上的版本才支援quartz 2.x,不然會出錯。至於原因,則是spring對於quartz的支援實現org.springframework.scheduling.quartz.CronTriggerBean繼承了org.quartz.CronTrigger,在quartz1.x系列中org.quartz.CronTrigger是個類,而在quartz2.x系列中org.quartz.CronTrigger變成了介面,從而造成無法用spring的方式配置quartz的觸發器(trigger)
編寫配置類
package com.zkml.reception.config;
import com.alibaba.druid.pool.DruidDataSource;
import com.zkml.reception.jobs.StatisticsJob;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.TriggerKey;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.quartz.CronTriggerFactoryBean;
import org.springframework.scheduling.quartz.JobDetailFactoryBean;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.sql.DataSource;
import java.io.IOException;
import java.util.Properties;
import java.util.concurrent.Executor;
/**
*
* @Author: Luzy
* @Date: 2020-07-06 16:05:53
* @Description: 分散式定時器配置類
**/
@Configuration
public class TaskConfig {
/** 定義叢集中job所屬組*/
private static final String JOB_DEFAULT_GROUP_NAME = "JOB_STATISTICS_GROUP";
/** 定義叢集中trigger所屬組*/
private static final String TRIGGER_DEFAULT_GROUP_NAME = "TRIGGER_STATISTICS_GROUP";
@Value("${spring.datasource.dynamic.datasource.master.url}")
private String url;
@Value("${spring.datasource.dynamic.datasource.master.username}")
private String username;
@Value("${spring.datasource.dynamic.datasource.master.password}")
private String password;
@Value("${spring.datasource.dynamic.datasource.master.driver-class-name}")
private String driver;
@Value("${corn.expression}")
private String corn;
@Autowired
private SpringJobFactory springJobFactory;
//開啟當前的任務排程器
@Bean
public Scheduler scheduler() throws Exception {
Scheduler scheduler = schedulerFactoryBean().getScheduler();
/* TriggerKey triggerKey1 = TriggerKey.triggerKey("trigger1", "TriggerTest11111");
*//*========如果有必要可以配置刪除任務,開始====================*//*
//停止觸發器
scheduler.pauseTrigger(triggerKey1);
//移除觸發器
scheduler.unscheduleJob(triggerKey1);
JobKey jobKey1 = JobKey.jobKey(" ------", "quartzTest--------");
//刪除任務
boolean b = scheduler.deleteJob(jobKey1);
System.out.println(b);
*//*=========結束====================*/
scheduler.start();
return scheduler;
}
//配置資料來源
//這裡可以不使用@Bean交給spring管理,否則可能出現預設資料來源的問題.
//@Bean
public DataSource druidDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
dataSource.setDriverClassName(driver);
return dataSource;
}
//配置quartz配置檔案
@Bean
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
// 在quartz.properties中的屬性被讀取並注入後再初始化物件
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
//配置定時任務
@Bean
public JobDetailFactoryBean job() {
JobDetailFactoryBean jobDetail = new JobDetailFactoryBean();
//配置任務的具體實現
jobDetail.setJobClass(StatisticsJob.class);
//是否持久化
jobDetail.setDurability(true);
//出現異常是否重新執行
jobDetail.setRequestsRecovery(true);
//配置定時任務資訊
jobDetail.setGroup(JOB_DEFAULT_GROUP_NAME);
jobDetail.setName("大資料統計定時任務");
jobDetail.setDescription("公務接待資料視覺化分析統計");
return jobDetail;
}
//配置任務定時規則
@Bean
public CronTriggerFactoryBean trigger() {
CronTriggerFactoryBean cronTrigger = new CronTriggerFactoryBean();
cronTrigger.setGroup(TRIGGER_DEFAULT_GROUP_NAME);
cronTrigger.setName("大資料統計定時器規則");
cronTrigger.setJobDetail(job().getObject());
cronTrigger.setCronExpression(corn);
return cronTrigger;
}
//配置任務排程工廠,用來生成任務排程器,這是quartz的核心
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
//將自定義的MyJobFactory注入配置類,並新增如下配置,
//配置使用spring的autowired的物件,在job中進行物件的注入
factory.setJobFactory(springJobFactory);
//設定延時啟動,保證job中的屬性的注入
factory.setStartupDelay(5);
//開啟更新job
factory.setOverwriteExistingJobs(true);
//如果不配置就會使用quartz.properties中的instanceName
factory.setSchedulerName("Statistics_Cluster_Scheduler");
//配置資料來源,這是quartz使用的表的資料庫存放位置
factory.setDataSource(druidDataSource());
//設定例項在spring容器中的key
factory.setApplicationContextSchedulerContextKey("applicationContext");
//配置執行緒池
factory.setTaskExecutor(schedulerThreadPool());
//配置配置檔案
factory.setQuartzProperties(quartzProperties());
//配置任務執行規則,引數是一個可變陣列
// factory.setTriggers(trigger1().getObject(),trigger2().getObject());
factory.setTriggers(trigger().getObject());
return factory;
}
//執行緒池配置
@Bean
public Executor schedulerThreadPool() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(50);
return executor;
}
}
編寫任務類
定時任務需要實現job介面,但是quartz已經有了一個簡單的抽象實現,簡化了程式碼量.只需要直接繼承即可
package com.zkml.reception.jobs;
import com.zkml.common.util.CopyUtil;
import com.zkml.reception.entity.PlanStaticLever;
import com.zkml.reception.entity.PlanStaticType;
import com.zkml.reception.entity.PlanStaticVisit;
import com.zkml.reception.entity.SettlementStatic;
import com.zkml.reception.response.StatisticsResponse;
import com.zkml.reception.service.*;
import com.zkml.reception.util.PrimaryKeyUtil;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import java.util.Date;
import java.util.List;
/**
* @Author: Luzy
* @Date: 2020-07-06 15:36
* @Description: 大資料統計job
*/
@Component
public class StatisticsJob extends QuartzJobBean {
@Autowired
private PlanService planService;
@Autowired
private PlanStaticLeverService planStaticLeverService;
@Autowired
private SettlementStaticService settlementStaticService;
@Autowired
private PlanStaticTypeService planStaticTypeService;
@Autowired
private PlanStaticVisitService planStaticVisitService;
@Autowired
private SettlementService settlementService;
@Override
protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("***********StatisticsJob中的executeInternal方法執行了***********"+new Date());
// //公務接待任務次數
// List<Map<String, Object>> taskCountForCurrentMonth = planService.getTaskCountForCurrentMonth();
//
//各級來賓人數統計
List<StatisticsResponse.AllLevelPersons> planCountByReceptLevel = planService.getPlanCountByReceptLevel();
List<PlanStaticLever> planStaticLevers = CopyUtil.copyBeanList(planCountByReceptLevel, PlanStaticLever.class);
if (!StringUtils.isEmpty(planStaticLevers)){
planStaticLevers = PrimaryKeyUtil.guestStatistics(planStaticLevers);
planStaticLeverService.saveOrUpdateBatch(planStaticLevers);
}
//來訪型別統計
List<StatisticsResponse.ClassifyByVisitType> countByVisitType = planService.getCountByVisitType();
List<PlanStaticVisit> planStaticVisits = CopyUtil.copyBeanList(countByVisitType, PlanStaticVisit.class);
if (!StringUtils.isEmpty(planStaticVisits)){
planStaticVisits = PrimaryKeyUtil.visitTypeStatistics(planStaticVisits);
planStaticVisitService.saveOrUpdateBatch(planStaticVisits);
}
//接待型別統計
List<StatisticsResponse.ClassifyByReceptLevel> planByReceptLevel = planService.getPlanByReceptLevel();
List<PlanStaticType> planStaticTypes = CopyUtil.copyBeanList(planByReceptLevel, PlanStaticType.class);
if (!StringUtils.isEmpty(planStaticTypes)){
planStaticTypes = PrimaryKeyUtil.receptionTypeStatistics(planStaticTypes);
planStaticTypeService.saveOrUpdateBatch(planStaticTypes);
}
//支出分類統計
List<StatisticsResponse.Expenditure> planCostsForCurrMonth = settlementService.getPlanCostsForCurrMonth();
List<SettlementStatic> settlementStatics = CopyUtil.copyBeanList(planCostsForCurrMonth, SettlementStatic.class);
if (!StringUtils.isEmpty(settlementStatics)){
settlementStatics = PrimaryKeyUtil.expenditureStatistics(settlementStatics);
settlementStaticService.saveOrUpdateBatch(settlementStatics);
}
}
}
這裡我定時規則為每晚11點觸發
application.yml部分
corn:
expression: 0 0 23 * * ?