@EnableScheduling
注解和@Scheduled注解實現(xiàn)定時任務(wù),也可以通過SchedulingConfigurer接口來實現(xiàn)定時任務(wù)。但是這兩種方式不能動態(tài)添加、刪除、啟動、停止任務(wù)。要實現(xiàn)動態(tài)增刪啟停定時任務(wù)功能,比較廣泛的做法是集成Quartz框架。但是本人的開發(fā)原則是:在滿足項目需求的情況下,盡量少的依賴其它框架,避免項目過于臃腫和復(fù)雜。
查看spring-context這個jar包中org.springframework.scheduling.ScheduledTaskRegistrar
這個類的源代碼,發(fā)現(xiàn)可以通過改造這個類就能實現(xiàn)動態(tài)增刪啟停定時任務(wù)功能。
![e8f20370-1085-11ec-8fb8-12bb97331649.jpg](https://file.elecfans.com/web2/M00/15/C6/pYYBAGFNMLeALQsgAAAcvjHENHc323.jpg)
![e90122f6-1085-11ec-8fb8-12bb97331649.jpg](https://file.elecfans.com/web2/M00/15/C6/pYYBAGFNMLeACs9mAACMWexFmjA046.jpg)
添加執(zhí)行定時任務(wù)的線程池配置類
@Configuration
publicclassSchedulingConfig{
@Bean
publicTaskSchedulertaskScheduler(){
ThreadPoolTaskSchedulertaskScheduler=newThreadPoolTaskScheduler();
//定時任務(wù)執(zhí)行線程池核心線程數(shù)
taskScheduler.setPoolSize(4);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
returntaskScheduler;
}
}
添加ScheduledFuture的包裝類。ScheduledFuture是ScheduledExecutorService定時任務(wù)線程池的執(zhí)行結(jié)果。
publicfinalclassScheduledTask{
volatileScheduledFuture>future;
/**
*取消定時任務(wù)
*/
publicvoidcancel(){
ScheduledFuture>future=this.future;
if(future!=null){
future.cancel(true);
}
}
}
添加Runnable接口實現(xiàn)類,被定時任務(wù)線程池調(diào)用,用來執(zhí)行指定bean里面的方法。
publicclassSchedulingRunnableimplementsRunnable{
privatestaticfinalLoggerlogger=LoggerFactory.getLogger(SchedulingRunnable.class);
privateStringbeanName;
privateStringmethodName;
privateStringparams;
publicSchedulingRunnable(StringbeanName,StringmethodName){
this(beanName,methodName,null);
}
publicSchedulingRunnable(StringbeanName,StringmethodName,Stringparams){
this.beanName=beanName;
this.methodName=methodName;
this.params=params;
}
@Override
publicvoidrun(){
logger.info("定時任務(wù)開始執(zhí)行- bean:{},方法:{},參數(shù):{}",beanName,methodName,params);
longstartTime=System.currentTimeMillis();
try{
Objecttarget=SpringContextUtils.getBean(beanName);
Methodmethod=null;
if(StringUtils.isNotEmpty(params)){
method=target.getClass().getDeclaredMethod(methodName,String.class);
}else{
method=target.getClass().getDeclaredMethod(methodName);
}
ReflectionUtils.makeAccessible(method);
if(StringUtils.isNotEmpty(params)){
method.invoke(target,params);
}else{
method.invoke(target);
}
}catch(Exceptionex){
logger.error(String.format("定時任務(wù)執(zhí)行異常- bean:%s,方法:%s,參數(shù):%s ",beanName,methodName,params),ex);
}
longtimes=System.currentTimeMillis()-startTime;
logger.info("定時任務(wù)執(zhí)行結(jié)束- bean:{},方法:{},參數(shù):{},耗時:{}毫秒",beanName,methodName,params,times);
}
@Override
publicbooleanequals(Objecto){
if(this==o)returntrue;
if(o==null||getClass()!=o.getClass())returnfalse;
SchedulingRunnablethat=(SchedulingRunnable)o;
if(params==null){
returnbeanName.equals(that.beanName)&&
methodName.equals(that.methodName)&&
that.params==null;
}
returnbeanName.equals(that.beanName)&&
methodName.equals(that.methodName)&&
params.equals(that.params);
}
@Override
publicinthashCode(){
if(params==null){
returnObjects.hash(beanName,methodName);
}
returnObjects.hash(beanName,methodName,params);
}
}
添加定時任務(wù)注冊類,用來增加、刪除定時任務(wù)。
@Component
publicclassCronTaskRegistrarimplementsDisposableBean{
privatefinalMapscheduledTasks=newConcurrentHashMap<>(16);
@Autowired
privateTaskSchedulertaskScheduler;
publicTaskSchedulergetScheduler(){
returnthis.taskScheduler;
}
publicvoidaddCronTask(Runnabletask,StringcronExpression){
addCronTask(newCronTask(task,cronExpression));
}
publicvoidaddCronTask(CronTaskcronTask){
if(cronTask!=null){
Runnabletask=cronTask.getRunnable();
if(this.scheduledTasks.containsKey(task)){
removeCronTask(task);
}
this.scheduledTasks.put(task,scheduleCronTask(cronTask));
}
}
publicvoidremoveCronTask(Runnabletask){
ScheduledTaskscheduledTask=this.scheduledTasks.remove(task);
if(scheduledTask!=null)
scheduledTask.cancel();
}
publicScheduledTaskscheduleCronTask(CronTaskcronTask){
ScheduledTaskscheduledTask=newScheduledTask();
scheduledTask.future=this.taskScheduler.schedule(cronTask.getRunnable(),cronTask.getTrigger());
returnscheduledTask;
}
@Override
publicvoiddestroy(){
for(ScheduledTasktask:this.scheduledTasks.values()){
task.cancel();
}
this.scheduledTasks.clear();
}
}
添加定時任務(wù)示例類
@Component("demoTask")
publicclassDemoTask{
publicvoidtaskWithParams(Stringparams){
System.out.println("執(zhí)行有參示例任務(wù):"+params);
}
publicvoidtaskNoParams(){
System.out.println("執(zhí)行無參示例任務(wù)");
}
}
定時任務(wù)數(shù)據(jù)庫表設(shè)計
添加定時任務(wù)實體類
publicclassSysJobPO{
/**
*任務(wù)ID
*/
privateIntegerjobId;
/**
*bean名稱
*/
privateStringbeanName;
/**
*方法名稱
*/
privateStringmethodName;
/**
*方法參數(shù)
*/
privateStringmethodParams;
/**
*cron表達(dá)式
*/
privateStringcronExpression;
/**
*狀態(tài)(1正常0暫停)
*/
privateIntegerjobStatus;
/**
*備注
*/
privateStringremark;
/**
*創(chuàng)建時間
*/
privateDatecreateTime;
/**
*更新時間
*/
privateDateupdateTime;
publicIntegergetJobId(){
returnjobId;
}
publicvoidsetJobId(IntegerjobId){
this.jobId=jobId;
}
publicStringgetBeanName(){
returnbeanName;
}
publicvoidsetBeanName(StringbeanName){
this.beanName=beanName;
}
publicStringgetMethodName(){
returnmethodName;
}
publicvoidsetMethodName(StringmethodName){
this.methodName=methodName;
}
publicStringgetMethodParams(){
returnmethodParams;
}
publicvoidsetMethodParams(StringmethodParams){
this.methodParams=methodParams;
}
publicStringgetCronExpression(){
returncronExpression;
}
publicvoidsetCronExpression(StringcronExpression){
this.cronExpression=cronExpression;
}
publicIntegergetJobStatus(){
returnjobStatus;
}
publicvoidsetJobStatus(IntegerjobStatus){
this.jobStatus=jobStatus;
}
publicStringgetRemark(){
returnremark;
}
publicvoidsetRemark(Stringremark){
this.remark=remark;
}
publicDategetCreateTime(){
returncreateTime;
}
publicvoidsetCreateTime(DatecreateTime){
this.createTime=createTime;
}
publicDategetUpdateTime(){
returnupdateTime;
}
publicvoidsetUpdateTime(DateupdateTime){
this.updateTime=updateTime;
}
}
booleansuccess=sysJobRepository.addSysJob(sysJob);
if(!success)
returnOperationResUtils.fail("新增失敗");
else{
if(sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())){
SchedulingRunnabletask=newSchedulingRunnable(sysJob.getBeanName(),sysJob.getMethodName(),sysJob.getMethodParams());
cronTaskRegistrar.addCronTask(task,sysJob.getCronExpression());
}
}
returnOperationResUtils.success();
修改定時任務(wù),先移除原來的任務(wù),再啟動新任務(wù)
booleansuccess=sysJobRepository.editSysJob(sysJob);
if(!success)
returnOperationResUtils.fail("編輯失敗");
else{
//先移除再添加
if(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())){
SchedulingRunnabletask=newSchedulingRunnable(existedSysJob.getBeanName(),existedSysJob.getMethodName(),existedSysJob.getMethodParams());
cronTaskRegistrar.removeCronTask(task);
}
if(sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())){
SchedulingRunnabletask=newSchedulingRunnable(sysJob.getBeanName(),sysJob.getMethodName(),sysJob.getMethodParams());
cronTaskRegistrar.addCronTask(task,sysJob.getCronExpression());
}
}
returnOperationResUtils.success();
刪除定時任務(wù)
booleansuccess=sysJobRepository.deleteSysJobById(req.getJobId());
if(!success)
returnOperationResUtils.fail("刪除失敗");
else{
if(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())){
SchedulingRunnabletask=newSchedulingRunnable(existedSysJob.getBeanName(),existedSysJob.getMethodName(),existedSysJob.getMethodParams());
cronTaskRegistrar.removeCronTask(task);
}
}
returnOperationResUtils.success();
定時任務(wù)啟動/停止?fàn)顟B(tài)切換
if(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal())){
SchedulingRunnabletask=newSchedulingRunnable(existedSysJob.getBeanName(),existedSysJob.getMethodName(),existedSysJob.getMethodParams());
cronTaskRegistrar.addCronTask(task,existedSysJob.getCronExpression());
}else{
SchedulingRunnabletask=newSchedulingRunnable(existedSysJob.getBeanName(),existedSysJob.getMethodName(),existedSysJob.getMethodParams());
cronTaskRegistrar.removeCronTask(task);
}
添加實現(xiàn)了CommandLineRunner接口的SysJobRunner類,當(dāng)spring boot項目啟動完成后,加載數(shù)據(jù)庫里狀態(tài)為正常的定時任務(wù)。
@Service
publicclassSysJobRunnerimplementsCommandLineRunner{
privatestaticfinalLoggerlogger=LoggerFactory.getLogger(SysJobRunner.class);
@Autowired
privateISysJobRepositorysysJobRepository;
@Autowired
privateCronTaskRegistrarcronTaskRegistrar;
@Override
publicvoidrun(String...args){
//初始加載數(shù)據(jù)庫里狀態(tài)為正常的定時任務(wù)
ListjobList=sysJobRepository.getSysJobListByStatus(SysJobStatus.NORMAL.ordinal());
if(CollectionUtils.isNotEmpty(jobList)){
for(SysJobPOjob:jobList){
SchedulingRunnabletask=newSchedulingRunnable(job.getBeanName(),job.getMethodName(),job.getMethodParams());
cronTaskRegistrar.addCronTask(task,job.getCronExpression());
}
logger.info("定時任務(wù)已加載完畢...");
}
}
}
工具類SpringContextUtils,用來從spring容器里獲取bean
@Component
publicclassSpringContextUtilsimplementsApplicationContextAware{
privatestaticApplicationContextapplicationContext;
@Override
publicvoidsetApplicationContext(ApplicationContextapplicationContext)
throwsBeansException{
SpringContextUtils.applicationContext=applicationContext;
}
publicstaticObjectgetBean(Stringname){
returnapplicationContext.getBean(name);
}
publicstaticTgetBean(ClassrequiredType) {
returnapplicationContext.getBean(requiredType);
}
publicstaticTgetBean(Stringname,ClassrequiredType) {
returnapplicationContext.getBean(name,requiredType);
}
publicstaticbooleancontainsBean(Stringname){
returnapplicationContext.containsBean(name);
}
publicstaticbooleanisSingleton(Stringname){
returnapplicationContext.isSingleton(name);
}
publicstaticClass?extends?Object>getType(Stringname){
returnapplicationContext.getType(name);
}
}
本文完,參考本文代碼可成功運行,親測!
(感謝閱讀,希望對你所有幫助)來源:www.jianshu.com/p/0f68936393fd-
源代碼
+關(guān)注
關(guān)注
96文章
2946瀏覽量
66985 -
spring
+關(guān)注
關(guān)注
0文章
340瀏覽量
14398 -
Boot
+關(guān)注
關(guān)注
0文章
150瀏覽量
35952 -
SpringBoot
+關(guān)注
關(guān)注
0文章
174瀏覽量
201
原文標(biāo)題:告別硬編碼,SpringBoot實現(xiàn)動態(tài)增刪啟停定時任務(wù)
文章出處:【微信號:AndroidPush,微信公眾號:Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
Linux計劃任務(wù)介紹
mysql定時備份任務(wù)
PL5501(汽車啟停系統(tǒng)、工業(yè)PC電源、USBPD快充、車載充電器、HUB等產(chǎn)品)
拉板小車啟停限位開關(guān)MN8-M18G12-POD1-30-Y技術(shù)特性
變頻器外接啟停按鈕如何接線
ESP8266如何實現(xiàn)時間小于3us的定時任務(wù)?
智能插座“云”時代:定時任務(wù)與事件驅(qū)動的創(chuàng)新管理
![智能插座“云”時代:<b class='flag-5'>定時任務(wù)</b>與事件驅(qū)動的創(chuàng)新管理](https://file1.elecfans.com/web2/M00/FC/9F/wKgZomaU9ZqAUU92AAMpPuGMs7k627.jpg)
定時器的工作方式介紹
長持續(xù)時間定時器電路圖 時間定時器的工作原理和功能
![長持續(xù)時間<b class='flag-5'>定時</b>器電路圖 時間<b class='flag-5'>定時</b>器的工作原理和功能](https://file1.elecfans.com/web2/M00/F2/66/wKgZomZ5O3qAM22OAAFPBYcZxaY870.png)
PLC工程示例之步進(jìn)電機(jī)啟停
為了低功耗每2秒將STM32F4的ADC做一次standby啟停可不可行?
在物通博聯(lián)工業(yè)智能網(wǎng)關(guān)的本地配置界面(WEB)直接配置定時控制任務(wù)
![在物通博聯(lián)工業(yè)智能網(wǎng)關(guān)的本地配置界面(WEB)直接配置<b class='flag-5'>定時</b>控制<b class='flag-5'>任務(wù)</b>](https://file1.elecfans.com//web2/M00/D7/D1/wKgZomYozv2AUbD2AABMXMGidUg724.jpg)
基于VC的三相異步電機(jī)啟停系統(tǒng)的設(shè)計
![基于VC的三相異步電機(jī)<b class='flag-5'>啟</b><b class='flag-5'>停</b>系統(tǒng)的設(shè)計](https://file1.elecfans.com/web2/M00/BD/2C/wKgZomWo7U2AG-S0AAICwD617RI311.png)
評論