Spring Boot 2 整合 QuartJob 實(shí)現(xiàn)定時(shí)器實(shí)時(shí)管理功能
一、QuartJob簡介
1、一句話描述
Quartz是一個(gè)完全由java編寫的開源作業(yè)調(diào)度框架,形式簡易,功能強(qiáng)大。
2、核心API
(1)、Scheduler
代表一個(gè) Quartz 的獨(dú)立運(yùn)行容器,Scheduler 將 Trigger 綁定到特定 JobDetail, 這樣當(dāng) Trigger 觸發(fā)時(shí), 對應(yīng)的 Job 就會(huì)被調(diào)度。
(2)、Trigger
描述 Job 執(zhí)行的時(shí)間觸發(fā)規(guī)則。主要有 SimpleTrigger 和 CronTrigger 兩個(gè)子類,通過一個(gè) TriggerKey 唯一標(biāo)識。
(3)、Job
定義一個(gè)任務(wù),規(guī)定了任務(wù)是執(zhí)行時(shí)的行為。JobExecutionContext 提供了調(diào)度器的上下文信息,Job 的數(shù)據(jù)可從 JobDataMap 中獲取。
(4)、JobDetail
Quartz 在每次執(zhí)行 Job 時(shí),都重新創(chuàng)建一個(gè) Job 實(shí)例,所以它不直接接受一個(gè) Job 的實(shí)例,相反它接收一個(gè) Job 實(shí)現(xiàn)類。描述 Job 的實(shí)現(xiàn)類及其它相關(guān)的靜態(tài)信息,如 Job 名字、描述等。
二、與SpringBoot2.0 整合
1、項(xiàng)目結(jié)構(gòu)

版本描述
spring-boot:2.1.3.RELEASE
quart-job:2.3.0
2、定時(shí)器配置
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參數(shù)配置
Properties prop = new Properties();
// Schedule調(diào)度器的實(shí)體名字
prop.put("org.quartz.scheduler.instanceName", "HuskyScheduler");
// 設(shè)置為AUTO時(shí)使用,默認(rèn)的實(shí)現(xiàn)org.quartz.scheduler.SimpleInstanceGenerator是基于主機(jī)名稱和時(shí)間戳生成。
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在運(yùn)行時(shí)用來存儲(chǔ)相關(guān)的信息
// JDBCJobStore和JobStoreTX都使用關(guān)系數(shù)據(jù)庫來存儲(chǔ)Schedule相關(guān)的信息。
// JobStoreTX在每次執(zhí)行任務(wù)后都使用commit或者rollback來提交更改。
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
// 集群配置:如果有多個(gè)調(diào)度器實(shí)體的話則必須設(shè)置為true
prop.put("org.quartz.jobStore.isClustered", "true");
// 集群配置:檢查集群下的其他調(diào)度器實(shí)體的時(shí)間間隔
prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
// 設(shè)置一個(gè)頻度(毫秒),用于實(shí)例報(bào)告給集群中的其他實(shí)例
prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
// 觸發(fā)器觸發(fā)失敗后再次觸犯的時(shí)間間隔
prop.put("org.quartz.jobStore.misfireThreshold", "12000");
// 數(shù)據(jù)庫表前綴
prop.put("org.quartz.jobStore.tablePrefix", "qrtz_");
// 從 LOCKS 表查詢一行并對這行記錄加鎖的 SQL 語句
prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
// 定時(shí)器工廠配置
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
factory.setQuartzProperties(prop);
factory.setSchedulerName("HuskyScheduler");
factory.setStartupDelay(30);
factory.setApplicationContextSchedulerContextKey("applicationContextKey");
// 可選,QuartzScheduler 啟動(dòng)時(shí)更新己存在的Job
factory.setOverwriteExistingJobs(true);
// 設(shè)置自動(dòng)啟動(dòng),默認(rèn)為true
factory.setAutoStartup(true);
return factory;
}
}
3、定時(shí)器管理工具
import com.quart.job.entity.ScheduleJobBean;
import org.quartz.*;
/**
* 定時(shí)器工具類
*/
public class ScheduleUtil {
private ScheduleUtil (){}
private static final String SCHEDULE_NAME = "HUSKY_" ;
/**
* 觸發(fā)器 KEY
*/
public static TriggerKey getTriggerKey(Long jobId){
return TriggerKey.triggerKey(SCHEDULE_NAME+jobId) ;
}
/**
* 定時(shí)器 Key
*/
public static JobKey getJobKey (Long jobId){
return JobKey.jobKey(SCHEDULE_NAME+jobId) ;
}
/**
* 表達(dá)式觸發(fā)器
*/
public static CronTrigger getCronTrigger (Scheduler scheduler,Long jobId){
try {
return (CronTrigger)scheduler.getTrigger(getTriggerKey(jobId)) ;
} catch (SchedulerException e){
throw new RuntimeException("getCronTrigger Fail",e) ;
}
}
/**
* 創(chuàng)建定時(shí)器
*/
public static void createJob (Scheduler scheduler, ScheduleJobBean scheduleJob){
try {
// 構(gòu)建定時(shí)器
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) ;
// 如果該定時(shí)器處于暫停狀態(tài)
if (scheduleJob.getStatus() == 1){
pauseJob(scheduler,scheduleJob.getJobId()) ;
}
} catch (SchedulerException e){
throw new RuntimeException("createJob Fail",e) ;
}
}
/**
* 更新定時(shí)任務(wù)
*/
public static void updateJob(Scheduler scheduler, ScheduleJobBean scheduleJob) {
try {
// 構(gòu)建定時(shí)器
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);
// 如果該定時(shí)器處于暫停狀態(tài)
if(scheduleJob.getStatus() == 1){
pauseJob(scheduler, scheduleJob.getJobId());
}
} catch (SchedulerException e) {
throw new RuntimeException("updateJob Fail",e) ;
}
}
/**
* 停止定時(shí)器
*/
public static void pauseJob (Scheduler scheduler,Long jobId){
try {
scheduler.pauseJob(getJobKey(jobId));
} catch (SchedulerException e){
throw new RuntimeException("pauseJob Fail",e) ;
}
}
/**
* 恢復(fù)定時(shí)器
*/
public static void resumeJob (Scheduler scheduler,Long jobId){
try {
scheduler.resumeJob(getJobKey(jobId));
} catch (SchedulerException e){
throw new RuntimeException("resumeJob Fail",e) ;
}
}
/**
* 刪除定時(shí)器
*/
public static void deleteJob (Scheduler scheduler,Long jobId){
try {
scheduler.deleteJob(getJobKey(jobId));
} catch (SchedulerException e){
throw new RuntimeException("deleteJob Fail",e) ;
}
}
/**
* 執(zhí)行定時(shí)器
*/
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、定時(shí)器執(zhí)行和日志
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;
/**
* 定時(shí)器執(zhí)行日志記錄
*/
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") ;
// 定時(shí)器日志記錄
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 {
// 加載并執(zhí)行定時(shí)器的 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("定時(shí)器 === >> "+jobBean.getJobId()+"執(zhí)行成功,耗時(shí) === >> " + executeTime);
} catch (Exception e){
// 異常信息
long executeTime = System.currentTimeMillis() - beginTime;
logBean.setTimes((int)executeTime);
logBean.setStatus(1);
logBean.setError(e.getMessage());
} finally {
scheduleJobLogService.insert(logBean) ;
}
}
}
三、定時(shí)器服務(wù)封裝
1、定時(shí)器初始化
@Service
public class ScheduleJobServiceImpl implements ScheduleJobService {
@Resource
private Scheduler scheduler ;
@Resource
private ScheduleJobMapper scheduleJobMapper ;
/**
* 定時(shí)器初始化
*/
@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、添加定時(shí)器
@Override
@Transactional(rollbackFor = Exception.class)
public int insert(ScheduleJobBean record) {
ScheduleUtil.createJob(scheduler,record);
return scheduleJobMapper.insert(record);
}
3、立即執(zhí)行一次定時(shí)器
@Override
@Transactional(rollbackFor = Exception.class)
public void run(Long jobId) {
ScheduleJobBean scheduleJobBean = scheduleJobMapper.selectByPrimaryKey(jobId) ;
ScheduleUtil.run(scheduler,scheduleJobBean);
}
4、更新定時(shí)器
@Override
@Transactional(rollbackFor = Exception.class)
public int updateByPrimaryKeySelective(ScheduleJobBean record) {
ScheduleUtil.updateJob(scheduler,record);
return scheduleJobMapper.updateByPrimaryKeySelective(record);
}
5、停止定時(shí)器
@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、恢復(fù)定時(shí)器
@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、刪除定時(shí)器
@Override
@Transactional(rollbackFor = Exception.class)
public void delete(Long jobId) {
ScheduleUtil.deleteJob(scheduler, jobId);
scheduleJobMapper.deleteByPrimaryKey(jobId) ;
}
四、配置一個(gè)測試的定時(shí)器
1、定時(shí)接口封裝
public interface TaskService {
void run(String params);
}
2、測試定時(shí)器
@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("當(dāng)前時(shí)間::::"+format.format(new Date()));
}
}
五、源代碼
GitHub:知了一笑
https://github.com/cicadasmile/middle-ware-parent

總結(jié)
以上所述是小編給大家介紹的Spring Boot 2 整合 QuartJob 實(shí)現(xiàn)定時(shí)器實(shí)時(shí)管理功能,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會(huì)及時(shí)回復(fù)大家的。在此也非常感謝大家對腳本之家網(wǎng)站的支持!
如果你覺得本文對你有幫助,歡迎轉(zhuǎn)載,煩請注明出處,謝謝!
- Springboot集成定時(shí)器和多線程異步處理操作
- Spring Boot定時(shí)器創(chuàng)建及使用解析
- SpringBoot集成ElaticJob定時(shí)器的實(shí)現(xiàn)代碼
- SpringBoot 動(dòng)態(tài)定時(shí)器的使用方法
- 使用spring整合Quartz實(shí)現(xiàn)—定時(shí)器功能
- 詳解spring batch的使用和定時(shí)器Quart的使用
- 關(guān)于spring中定時(shí)器的使用教程
- java Quartz定時(shí)器任務(wù)與Spring task定時(shí)的幾種實(shí)現(xiàn)方法
- Java中Spring使用Quartz任務(wù)調(diào)度定時(shí)器
- Spring整合Quartz實(shí)現(xiàn)動(dòng)態(tài)定時(shí)器的示例代碼
- JAVA中 Spring定時(shí)器的兩種實(shí)現(xiàn)方式
- 淺析spring定時(shí)器的使用
相關(guān)文章
eclipse實(shí)現(xiàn)ElGamal數(shù)字簽名
這篇文章主要為大家詳細(xì)介紹了eclipse實(shí)現(xiàn)ElGamal數(shù)字簽名,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06
SpringCloud:feign對象傳參和普通傳參及遇到的坑解決
這篇文章主要介紹了SpringCloud:feign對象傳參和普通傳參及遇到的坑解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-03-03
詳解Java CompletableFuture使用方法以及與FutureTask的區(qū)別
CompletableFuture實(shí)現(xiàn)了CompletionStage接口和Future接口,前者是對后者的一個(gè)擴(kuò)展,增加了異步回調(diào)、流式處理、多個(gè)Future組合處理的能力,使Java在處理多任務(wù)的協(xié)同工作時(shí)更加順暢便利2021-10-10
在X分鐘內(nèi)學(xué)會(huì)C#的入門簡明教程
C#是一個(gè)優(yōu)雅的、類型安全的面向?qū)ο笳Z言。使用C#,開發(fā)者可以在.NET框架下構(gòu)建安全而強(qiáng)大的應(yīng)用程序,閱讀本文可以快速的入門C#編程語言,需要的朋友可以參考下2014-03-03
Java發(fā)送http請求調(diào)用第三方接口獲取token方式
這篇文章主要介紹了Java發(fā)送http請求調(diào)用第三方接口獲取token方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
spring 使用RabbitMQ進(jìn)行消息傳遞的示例代碼
這篇文章主要介紹了spring 使用RabbitMQ進(jìn)行消息傳遞的示例代碼,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-12-12
Spring依賴注入中的@Resource與@Autowired詳解
這篇文章主要介紹了Spring依賴注入中的@Resource與@Autowired詳解,提到Spring依賴注入,大家最先想到應(yīng)該是@Resource和@Autowired,對于Spring為什么要支持兩個(gè)這么類似的注解卻未提到,屬于知其然而不知其所以然,本文就來做詳細(xì)講解,需要的朋友可以參考下2023-09-09

