SpringBoot2.0高階案例(06):整合 QuartJob ,實現定時器實時管理
一、QuartJob簡介
1、一句話描述
Quartz是一個完全由java編寫的開源作業排程框架,形式簡易,功能強大。
2、核心API
(1)、Scheduler
代表一個 Quartz 的獨立執行容器,Scheduler 將 Trigger 繫結到特定 JobDetail, 這樣當 Trigger 觸發時, 對應的 Job 就會被排程。
(2)、Trigger
描述 Job 執行的時間觸發規則。主要有 SimpleTrigger 和 CronTrigger 兩個子類,通過一個 TriggerKey 唯一標識。
(3)、Job
定義一個任務,規定了任務是執行時的行為。JobExecutionContext 提供了排程器的上下文資訊,Job 的資料可從 JobDataMap 中獲取。
(4)、JobDetail
Quartz 在每次執行 Job 時,都重新建立一個 Job 例項,所以它不直接接受一個 Job 的例項,相反它接收一個 Job 實現類。描述 Job 的實現類及其它相關的靜態資訊,如 Job 名字、描述等。
二、與SpringBoot2.0 整合
1、專案結構
版本描述
spring-boot:2.1.3.RELEASE
quart-job:2.3.0
2、定時器配置
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.scheduling.quartz.SchedulerFactoryBean; import javax.sql.DataSource; import java.util.Properties; @Configuration public class ScheduleConfig { @Bean public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) { // Quartz引數配置 Properties prop = new Properties(); // Schedule排程器的實體名字 prop.put("org.quartz.scheduler.instanceName", "HuskyScheduler"); // 設定為AUTO時使用,預設的實現org.quartz.scheduler.SimpleInstanceGenerator是基於主機名稱和時間戳生成。 prop.put("org.quartz.scheduler.instanceId", "AUTO"); // 執行緒池配置 prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool"); prop.put("org.quartz.threadPool.threadCount", "20"); prop.put("org.quartz.threadPool.threadPriority", "5"); // JobStore配置:Scheduler在執行時用來儲存相關的資訊 // JDBCJobStore和JobStoreTX都使用關係資料庫來儲存Schedule相關的資訊。 // JobStoreTX在每次執行任務後都使用commit或者rollback來提交更改。 prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX"); // 叢集配置:如果有多個排程器實體的話則必須設定為true prop.put("org.quartz.jobStore.isClustered", "true"); // 叢集配置:檢查叢集下的其他排程器實體的時間間隔 prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000"); // 設定一個頻度(毫秒),用於例項報告給叢集中的其他例項 prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1"); // 觸發器觸發失敗後再次觸犯的時間間隔 prop.put("org.quartz.jobStore.misfireThreshold", "12000"); // 資料庫表字首 prop.put("org.quartz.jobStore.tablePrefix", "qrtz_"); // 從 LOCKS 表查詢一行並對這行記錄加鎖的 SQL 語句 prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?"); // 定時器工廠配置 SchedulerFactoryBean factory = new SchedulerFactoryBean(); factory.setDataSource(dataSource); factory.setQuartzProperties(prop); factory.setSchedulerName("HuskyScheduler"); factory.setStartupDelay(30); factory.setApplicationContextSchedulerContextKey("applicationContextKey"); // 可選,QuartzScheduler 啟動時更新己存在的Job factory.setOverwriteExistingJobs(true); // 設定自動啟動,預設為true factory.setAutoStartup(true); return factory; } }
3、定時器管理工具
import com.quart.job.entity.ScheduleJobBean; import org.quartz.*; /** * 定時器工具類 */ public class ScheduleUtil { private ScheduleUtil (){} private static final String SCHEDULE_NAME = "HUSKY_" ; /** * 觸發器 KEY */ public static TriggerKey getTriggerKey(Long jobId){ return TriggerKey.triggerKey(SCHEDULE_NAME+jobId) ; } /** * 定時器 Key */ public static JobKey getJobKey (Long jobId){ return JobKey.jobKey(SCHEDULE_NAME+jobId) ; } /** * 表示式觸發器 */ public static CronTrigger getCronTrigger (Scheduler scheduler,Long jobId){ try { return (CronTrigger)scheduler.getTrigger(getTriggerKey(jobId)) ; } catch (SchedulerException e){ throw new RuntimeException("getCronTrigger Fail",e) ; } } /** * 建立定時器 */ public static void createJob (Scheduler scheduler, ScheduleJobBean scheduleJob){ try { // 構建定時器 JobDetail jobDetail = JobBuilder.newJob(TaskJobLog.class).withIdentity(getJobKey(scheduleJob.getJobId())).build() ; CronScheduleBuilder scheduleBuilder = CronScheduleBuilder .cronSchedule(scheduleJob.getCronExpression()) .withMisfireHandlingInstructionDoNothing() ; CronTrigger trigger = TriggerBuilder.newTrigger() .withIdentity(getTriggerKey(scheduleJob.getJobId())) .withSchedule(scheduleBuilder).build() ; jobDetail.getJobDataMap().put(ScheduleJobBean.JOB_PARAM_KEY,scheduleJob); scheduler.scheduleJob(jobDetail,trigger) ; // 如果該定時器處於暫停狀態 if (scheduleJob.getStatus() == 1){ pauseJob(scheduler,scheduleJob.getJobId()) ; } } catch (SchedulerException e){ throw new RuntimeException("createJob Fail",e) ; } } /** * 更新定時任務 */ public static void updateJob(Scheduler scheduler, ScheduleJobBean scheduleJob) { try { // 構建定時器 TriggerKey triggerKey = getTriggerKey(scheduleJob.getJobId()); CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression()) .withMisfireHandlingInstructionDoNothing(); CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getJobId()); trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build(); trigger.getJobDataMap().put(ScheduleJobBean.JOB_PARAM_KEY, scheduleJob); scheduler.rescheduleJob(triggerKey, trigger); // 如果該定時器處於暫停狀態 if(scheduleJob.getStatus() == 1){ pauseJob(scheduler, scheduleJob.getJobId()); } } catch (SchedulerException e) { throw new RuntimeException("updateJob Fail",e) ; } } /** * 停止定時器 */ public static void pauseJob (Scheduler scheduler,Long jobId){ try { scheduler.pauseJob(getJobKey(jobId)); } catch (SchedulerException e){ throw new RuntimeException("pauseJob Fail",e) ; } } /** * 恢復定時器 */ public static void resumeJob (Scheduler scheduler,Long jobId){ try { scheduler.resumeJob(getJobKey(jobId)); } catch (SchedulerException e){ throw new RuntimeException("resumeJob Fail",e) ; } } /** * 刪除定時器 */ public static void deleteJob (Scheduler scheduler,Long jobId){ try { scheduler.deleteJob(getJobKey(jobId)); } catch (SchedulerException e){ throw new RuntimeException("deleteJob Fail",e) ; } } /** * 執行定時器 */ public static void run (Scheduler scheduler, ScheduleJobBean scheduleJob){ try { JobDataMap dataMap = new JobDataMap() ; dataMap.put(ScheduleJobBean.JOB_PARAM_KEY,scheduleJob); scheduler.triggerJob(getJobKey(scheduleJob.getJobId()),dataMap); } catch (SchedulerException e){ throw new RuntimeException("run Fail",e) ; } } }
4、定時器執行和日誌
import com.quart.job.entity.ScheduleJobBean;
import com.quart.job.entity.ScheduleJobLogBean;
import com.quart.job.service.ScheduleJobLogService;
import org.quartz.JobExecutionContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;
import java.lang.reflect.Method;
import java.util.Date;
/**
* 定時器執行日誌記錄
*/
public class TaskJobLog extends QuartzJobBean {
private static final Logger LOG = LoggerFactory.getLogger(TaskJobLog.class) ;
@Override
protected void executeInternal(JobExecutionContext context) {
ScheduleJobBean jobBean = (ScheduleJobBean)context.getMergedJobDataMap().get(ScheduleJobBean.JOB_PARAM_KEY) ;
ScheduleJobLogService scheduleJobLogService = (ScheduleJobLogService)SpringContextUtil.getBean("scheduleJobLogService") ;
// 定時器日誌記錄
ScheduleJobLogBean logBean = new ScheduleJobLogBean () ;
logBean.setJobId(jobBean.getJobId());
logBean.setBeanName(jobBean.getBeanName());
logBean.setParams(jobBean.getParams());
logBean.setCreateTime(new Date());
long beginTime = System.currentTimeMillis() ;
try {
// 載入並執行定時器的 run 方法
Object target = SpringContextUtil.getBean(jobBean.getBeanName());
Method method = target.getClass().getDeclaredMethod("run", String.class);
method.invoke(target, jobBean.getParams());
long executeTime = System.currentTimeMillis() - beginTime;
logBean.setTimes((int)executeTime);
logBean.setStatus(0);
LOG.info("定時器 === >> "+jobBean.getJobId()+"執行成功,耗時 === >> " + executeTime);
} catch (Exception e){
// 異常資訊
long executeTime = System.currentTimeMillis() - beginTime;
logBean.setTimes((int)executeTime);
logBean.setStatus(1);
logBean.setError(e.getMessage());
} finally {
scheduleJobLogService.insert(logBean) ;
}
}
}
三、定時器服務封裝
1、定時器初始化
@Service
public class ScheduleJobServiceImpl implements ScheduleJobService {
@Resource
private Scheduler scheduler ;
@Resource
private ScheduleJobMapper scheduleJobMapper ;
/**
* 定時器初始化
*/
@PostConstruct
public void init (){
ScheduleJobExample example = new ScheduleJobExample() ;
List<ScheduleJobBean> scheduleJobBeanList = scheduleJobMapper.selectByExample(example) ;
for (ScheduleJobBean scheduleJobBean : scheduleJobBeanList) {
CronTrigger cronTrigger = ScheduleUtil.getCronTrigger(scheduler,scheduleJobBean.getJobId()) ;
if (cronTrigger == null){
ScheduleUtil.createJob(scheduler,scheduleJobBean);
} else {
ScheduleUtil.updateJob(scheduler,scheduleJobBean);
}
}
}
}
2、新增定時器
@Override
@Transactional(rollbackFor = Exception.class)
public int insert(ScheduleJobBean record) {
ScheduleUtil.createJob(scheduler,record);
return scheduleJobMapper.insert(record);
}
3、立即執行一次定時器
@Override
@Transactional(rollbackFor = Exception.class)
public void run(Long jobId) {
ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ;
ScheduleUtil.run(scheduler,scheduleJobBean);
}
4、更新定時器
@Override
@Transactional(rollbackFor = Exception.class)
public int updateByPrimaryKeySelective(ScheduleJobBean record) {
ScheduleUtil.updateJob(scheduler,record);
return scheduleJobMapper.updateByPrimaryKeySelective(record);
}
5、停止定時器
@Override
@Transactional(rollbackFor = Exception.class)
public void pauseJob(Long jobId) {
ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ;
ScheduleUtil.pauseJob(scheduler,jobId);
scheduleJobBean.setStatus(1);
scheduleJobMapper.updateByPrimaryKeySelective(scheduleJobBean) ;
}
6、恢復定時器
@Override
@Transactional(rollbackFor = Exception.class)
public void resumeJob(Long jobId) {
ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ;
ScheduleUtil.resumeJob(scheduler,jobId);
scheduleJobBean.setStatus(0);
scheduleJobMapper.updateByPrimaryKeySelective(scheduleJobBean) ;
}
7、刪除定時器
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(Long jobId) {
ScheduleUtil.deleteJob(scheduler, jobId);
scheduleJobMapper.deleteByPrimaryKey(jobId) ;
}
四、配置一個測試的定時器
1、定時介面封裝
public interface TaskService {
void run(String params);
}
2、測試定時器
@Component("getTimeTask")
public class GetTimeTask implements TaskService {
private static final Logger LOG = LoggerFactory.getLogger(GetTimeTask.class.getName()) ;
private static final SimpleDateFormat format =
new SimpleDateFormat("yyyy-MM-dd HH:mm:ss") ;
@Override
public void run(String params) {
LOG.info("Params === >> " + params);
LOG.info("當前時間::::"+format.format(new Date()));
}
}
五、原始碼
GitHub地址:知了一笑
https://github.com/cicadasmile/middle-ware-parent
碼雲地址:知了一笑
https://gitee.com/cicadasmile/middle-ware-parent
相關推薦
SpringBoot2.0高階案例(06):整合 QuartJob ,實現定時器實時管理
一、QuartJob簡介 1、一句話描述 Quartz是一個完全由java編寫的開源作業排程框架,形式簡易,功能強大。 2、核心A
SpringBoot2.0高階案例(02) :整合 RocketMQ ,實現請求非同步處理
本文原始碼 碼雲地址:知了一笑 https://gitee.com/cicadasmile/middle-ware-parent
SpringBoot2.0高階案例(03):整合 JavaMail ,實現非同步傳送郵件
本文原始碼 碼雲地址:知了一笑 https://gitee.com/cicadasmile/middle-ware-parent
SpringBoot2.0高階案例(05):整合 Swagger2 ,構建介面管理介面
一、Swagger2簡介 1、Swagger2優點 整合到Spring Boot中,構建強大RESTful API文件。省去介面文
SpringBoot2.0高階案例(09):整合 ElasticSearch框架,實現高效能搜尋引擎
本文原始碼 碼雲地址:知了一笑 https://gitee.com/cicadasmile/middle-ware-parent
SpringBoot2.0高階案例(12):整合 SpringSecurity 框架,實現使用者許可權安全管理
一、Security簡介 1、基礎概念 Spring Security是一個能夠為基於Spring的企業應用系統提供宣告式的安全訪
SpringBoot2.0高階案例(10):整合 JWT 框架,解決Token跨域驗證問題
GitHub原始碼地址:知了一笑 https://github.com/cicadasmile/middle-ware-paren
SpringBoot2.0高階案例(08):整合 Dubbo框架 ,實現RPC服務遠端呼叫
一、Dubbo框架簡介 1、框架依賴 圖例說明: 1)圖中小方塊 Protocol, Cluster, Proxy, Servi
SpringBoot2.0高階案例(07) 整合:Redis叢集 ,實現訊息佇列場景
本文原始碼 GitHub地址:知了一笑 https://github.com/cicadasmile/middle-ware-pa
SpringBoot2高階案例(11):整合 FastDFS 中介軟體,實現檔案分散式管理
一、FastDFS簡介 1、FastDFS作用 FastDFS是一個開源的輕量級分散式檔案系統,它對檔案進行管理,功能包括:檔案儲
案例五:shell指令碼實現定時監控http服務的執行狀態
注意:監控方法可以為埠、程序、URL模擬訪問方式,或者三種方法綜合。 說明:由於截止到目前僅講了if語句,因此,就請大家用i
Sprinboot整合Quartz實現定時任務排程管理
Sprinboot整合Quartz實現定時任務排程管理 版本說明: springboot版本:2.0.0.RELEASE quartz版本:2.3.0 github地址:https://github.com/shirukai/quartz-demo.git
SpringBoot--01.SpringBoot2.0入門案例
一、SpringBoot簡介 1、SpringBoot概述(簡化配置、開箱即用) - 為所有 Spring 的開發者提供一個非常快速的、廣泛接受的入門體驗 - 開箱即用(啟動器starter-其實就是SpringBoot提供的一個jar包),但通過自己設定參 (.properties),
微服務 SpringBoot 2.0(九):整合Mybatis
我是SQL小白,我選Mybatis —— Java面試必修 引言 在第五章我們已經整合了Thymeleaf頁面框架,第七章也整合了JdbcTemplate,那今天我們再結合資料庫整合Mybatis框架 在接下來的文章中,我會用一個開源的部落格原始碼來做講解
Springboot2.0啟動報錯:java.lang.NoClassDefFoundError: ch/qos/logback/core/spi/LifeCycle
springboot2.0啟動報錯: java.lang.NoClassDefFoundError: ch/qos/logback/core/spi/LifeCycle at java.lang.ClassLoader.defineClass1(Native Met
springBoot2.0 MyBatis Redis 及RedisCache 整合附demo
springboot2.0 + mybatis 或者 springboot2.0 + redis 在網上可以找到很多資料,但是大都不全或者有這樣那樣的問題,所以便自己動手寫了個demo,能只用 yaml 配置的,儘量不再寫程式碼。 pom.xml <?xml ver
springboot學習入門簡易版四---springboot2.0靜態資源訪問及整合freemarker視圖層
nbsp 規則 pri stat path 整合 位置 啟動程序 -- 2.4.4 SpringBoot靜態資源訪問(9) Springboot默認提供靜態資源目錄位置需放在classpath下,目錄名需要符合如下規則 /static /public /resour
集合應用案例:編寫程序實現學生信息管理系統的錄入登錄
else 系統 tput img efault () 創建 輸入輸出 public 本編文章主要介紹一個關於集合的應用案例:完成班級學員錄入功能 (沒有持久化操作,每次重啟錄入的信息都保存不了) 一、需求: 創建學生類:添加以下屬性以及相應的構造函數!使用集合保存學員信息!
經典案例解讀:產品經理移動互聯網營銷管理
市場 san 模式 營銷管理 http 技能 速度 com 騰訊 經典案例解讀:產品經理移動互聯網營銷管理網盤地址:https://pan.baidu.com/s/1-gQPTSaNd2mOaA6D-ejlGg 提取碼: ggtb備用地址(騰訊微雲):https://sha
精通SpringBoot——第七篇:整合Redis實現快取
專案中用到快取是很常見的事情, 快取能夠提升系統訪問的速度,減輕對資料庫的壓力等好處。今天我們來講講怎麼在spring boot 中整合redis 實現對資料庫查詢結果的快取。 首先第一步要做的就是在pom.xml檔案新增spring-boot-starter-data-redis。 要整合快取,必