在线观看www成人影院-在线观看www日本免费网站-在线观看www视频-在线观看操-欧美18在线-欧美1级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線(xiàn)課程
  • 觀(guān)看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

求一種SpringBoot定時(shí)任務(wù)動(dòng)態(tài)管理通用解決方案

Android編程精選 ? 來(lái)源:CSDN ? 2023-02-03 09:49 ? 次閱讀

一、功能說(shuō)明

SpringBoot的定時(shí)任務(wù)的加強(qiáng)工具,實(shí)現(xiàn)對(duì)SpringBoot原生的定時(shí)任務(wù)進(jìn)行動(dòng)態(tài)管理,完全兼容原生@Scheduled注解,無(wú)需對(duì)原本的定時(shí)任務(wù)進(jìn)行修改

二、快速使用

具體的功能已經(jīng)封裝成SpringBoot-starter即插即用


com.github.guoyixing
spring-boot-starter-super-scheduled
0.3.1

三、實(shí)現(xiàn)原理

1、動(dòng)態(tài)管理實(shí)現(xiàn)

(1) 配置管理介紹

@Component("superScheduledConfig")
publicclassSuperScheduledConfig{
/**
*執(zhí)行定時(shí)任務(wù)的線(xiàn)程池
*/
privateThreadPoolTaskSchedulertaskScheduler;

/**
*定時(shí)任務(wù)名稱(chēng)與定時(shí)任務(wù)回調(diào)鉤子的關(guān)聯(lián)關(guān)系容器
*/
privateMapnameToScheduledFuture=newConcurrentHashMap<>();

/**
*定時(shí)任務(wù)名稱(chēng)與定時(shí)任務(wù)需要執(zhí)行的邏輯的關(guān)聯(lián)關(guān)系容器
*/
privateMapnameToRunnable=newConcurrentHashMap<>();

/**
*定時(shí)任務(wù)名稱(chēng)與定時(shí)任務(wù)的源信息的關(guān)聯(lián)關(guān)系容器
*/
privateMapnameToScheduledSource=newConcurrentHashMap<>();
/*普通的get/sets省略*/
}

(2) 使用后處理器攔截SpringBoot原本的定時(shí)任務(wù)

實(shí)現(xiàn)ApplicationContextAware接口拿到SpringBoot的上下文

實(shí)現(xiàn)BeanPostProcessor接口,將這個(gè)類(lèi)標(biāo)記為后處理器,后處理器會(huì)在每個(gè)bean實(shí)例化之后執(zhí)行

使用@DependsOn注解強(qiáng)制依賴(lài)SuperScheduledConfig類(lèi),讓SpringBoot實(shí)例化SuperScheduledPostProcessor類(lèi)之前先實(shí)例化SuperScheduledConfig類(lèi)

主要實(shí)現(xiàn)邏輯在postProcessAfterInitialization()方法中

ff50efb0-a33b-11ed-bfe3-dac502259ad0.png

@DependsOn({"superScheduledConfig"})
@Component
@Order
publicclassSuperScheduledPostProcessorimplementsBeanPostProcessor,ApplicationContextAware{
protectedfinalLoglogger=LogFactory.getLog(getClass());

privateApplicationContextapplicationContext;

/**
*實(shí)例化bean之前的操作
*@parambeanbean實(shí)例
*@parambeanNamebean的Name
*/
@Override
publicObjectpostProcessBeforeInitialization(Objectbean,StringbeanName)throwsBeansException{
returnbean;
}

/**
*實(shí)例化bean之后的操作
*@parambeanbean實(shí)例
*@parambeanNamebean的Name
*/
@Override
publicObjectpostProcessAfterInitialization(Objectbean,
StringbeanName)throwsBeansException{
//1.獲取配置管理器
SuperScheduledConfigsuperScheduledConfig=applicationContext.getBean(SuperScheduledConfig.class);

//2.獲取當(dāng)前實(shí)例化完成的bean的所有方法
Method[]methods=bean.getClass().getDeclaredMethods();
//循環(huán)處理對(duì)每個(gè)方法逐一處理
if(methods.length>0){
for(Methodmethod:methods){
//3.嘗試在該方法上獲取@Scheduled注解(SpringBoot的定時(shí)任務(wù)注解)
Scheduledannotation=method.getAnnotation(Scheduled.class);
//如果無(wú)法獲取到@Scheduled注解,就跳過(guò)這個(gè)方法
if(annotation==null){
continue;
}
//4.創(chuàng)建定時(shí)任務(wù)的源屬性
//創(chuàng)建定時(shí)任務(wù)的源屬性(用來(lái)記錄定時(shí)任務(wù)的配置,初始化的時(shí)候記錄的是注解上原本的屬性)
ScheduledSourcescheduledSource=newScheduledSource(annotation,method,bean);
//對(duì)注解上獲取到源屬性中的屬性進(jìn)行檢測(cè)
if(!scheduledSource.check()){
thrownewSuperScheduledException("在"+beanName+"Bean中"+method.getName()+"方法的注解參數(shù)錯(cuò)誤");
}
//生成定時(shí)任務(wù)的名稱(chēng)(id),使用beanName+“.”+方法名
Stringname=beanName+"."+method.getName();
//將以key-value的形式,將源數(shù)據(jù)存入配置管理器中,key:定時(shí)任務(wù)的名稱(chēng)value:源數(shù)據(jù)
superScheduledConfig.addScheduledSource(name,scheduledSource);
try{
//5.將原本SpringBoot的定時(shí)任務(wù)取消掉
clearOriginalScheduled(annotation);
}catch(Exceptione){
thrownewSuperScheduledException("在關(guān)閉原始方法"+beanName+method.getName()+"時(shí)出現(xiàn)錯(cuò)誤");
}
}
}
//最后bean保持原有返回
returnbean;
}

/**
*修改注解原先的屬性
*@paramannotation注解實(shí)例對(duì)象
*@throwsException
*/
privatevoidclearOriginalScheduled(Scheduledannotation)throwsException{
changeAnnotationValue(annotation,"cron",Scheduled.CRON_DISABLED);
changeAnnotationValue(annotation,"fixedDelay",-1L);
changeAnnotationValue(annotation,"fixedDelayString","");
changeAnnotationValue(annotation,"fixedRate",-1L);
changeAnnotationValue(annotation,"fixedRateString","");
changeAnnotationValue(annotation,"initialDelay",-1L);
changeAnnotationValue(annotation,"initialDelayString","");
}


/**
*獲取SpringBoot的上下文
*@paramapplicationContextSpringBoot的上下文
*/
@Override
publicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{
this.applicationContext=applicationContext;
}
}

(3) 使用ApplicationRunner初始化自定義的定時(shí)任務(wù)運(yùn)行器

實(shí)現(xiàn)ApplicationContextAware接口拿到SpringBoot的上下文

使用@DependsOn注解強(qiáng)制依賴(lài)threadPoolTaskScheduler類(lèi)

實(shí)現(xiàn)ApplicationRunner接口,在所有bean初始化結(jié)束之后,運(yùn)行自定義邏輯

主要實(shí)現(xiàn)邏輯在run()方法中

ff6ca778-a33b-11ed-bfe3-dac502259ad0.png

@DependsOn("threadPoolTaskScheduler")
@Component
publicclassSuperScheduledApplicationRunnerimplementsApplicationRunner,ApplicationContextAware{
protectedfinalLoglogger=LogFactory.getLog(getClass());
privateDateTimeFormatterdf=DateTimeFormatter.ofPattern("yyyy-MM-ddHHss");
privateApplicationContextapplicationContext;

/**
*定時(shí)任務(wù)配置管理器
*/
@Autowired
privateSuperScheduledConfigsuperScheduledConfig;
/**
*定時(shí)任務(wù)執(zhí)行線(xiàn)程
*/
@Autowired
privateThreadPoolTaskSchedulerthreadPoolTaskScheduler;

@Override
publicvoidrun(ApplicationArgumentsargs){
//1.定時(shí)任務(wù)配置管理器中緩存定時(shí)任務(wù)執(zhí)行線(xiàn)程
superScheduledConfig.setTaskScheduler(threadPoolTaskScheduler);
//2.獲取所有定時(shí)任務(wù)源數(shù)據(jù)
MapnameToScheduledSource=superScheduledConfig.getNameToScheduledSource();
//逐一處理定時(shí)任務(wù)
for(Stringname:nameToScheduledSource.keySet()){
//3.獲取定時(shí)任務(wù)源數(shù)據(jù)
ScheduledSourcescheduledSource=nameToScheduledSource.get(name);
//4.獲取所有增強(qiáng)類(lèi)
String[]baseStrengthenBeanNames=applicationContext.getBeanNamesForType(BaseStrengthen.class);
//5.創(chuàng)建執(zhí)行控制器
SuperScheduledRunnablerunnable=newSuperScheduledRunnable();
//配置執(zhí)行控制器
runnable.setMethod(scheduledSource.getMethod());
runnable.setBean(scheduledSource.getBean());
//6.逐一處理增強(qiáng)類(lèi)(增強(qiáng)器實(shí)現(xiàn)原理后面具體分析)
Listpoints=newArrayList<>(baseStrengthenBeanNames.length);
for(StringbaseStrengthenBeanName:baseStrengthenBeanNames){
//7.將增強(qiáng)器代理成point
ObjectbaseStrengthenBean=applicationContext.getBean(baseStrengthenBeanName);
//創(chuàng)建代理
Pointproxy=ProxyUtils.getInstance(Point.class,newRunnableBaseInterceptor(baseStrengthenBean,runnable));
proxy.setSuperScheduledName(name);
//8.所有的points連成起來(lái)
points.add(proxy);
}
//將point形成調(diào)用鏈
runnable.setChain(newChain(points));
//將執(zhí)行邏輯封裝并緩存到定時(shí)任務(wù)配置管理器中
superScheduledConfig.addRunnable(name,runnable::invoke);
try{
//8.啟動(dòng)定時(shí)任務(wù)
ScheduledFutureschedule=ScheduledFutureFactory.create(threadPoolTaskScheduler
,scheduledSource,runnable::invoke);
//將線(xiàn)程回調(diào)鉤子存到任務(wù)配置管理器中
superScheduledConfig.addScheduledFuture(name,schedule);
logger.info(df.format(LocalDateTime.now())+"任務(wù)"+name+"已經(jīng)啟動(dòng)...");

}catch(Exceptione){
thrownewSuperScheduledException("任務(wù)"+name+"啟動(dòng)失敗,錯(cuò)誤信息:"+e.getLocalizedMessage());
}
}
}

@Override
publicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{
this.applicationContext=applicationContext;
}
}

(4) 進(jìn)行動(dòng)態(tài)管理

@Component
publicclassSuperScheduledManager{
protectedfinalLoglogger=LogFactory.getLog(getClass());
privateDateTimeFormatterdf=DateTimeFormatter.ofPattern("yyyy-MM-ddHHss");

@Autowired
privateSuperScheduledConfigsuperScheduledConfig;

/**
*修改Scheduled的執(zhí)行周期
*
*@paramnamescheduled的名稱(chēng)
*@paramcroncron表達(dá)式
*/
publicvoidsetScheduledCron(Stringname,Stringcron){
//終止原先的任務(wù)
cancelScheduled(name);
//創(chuàng)建新的任務(wù)
ScheduledSourcescheduledSource=superScheduledConfig.getScheduledSource(name);
scheduledSource.clear();
scheduledSource.setCron(cron);
addScheduled(name,scheduledSource);
}

/**
*修改Scheduled的fixedDelay
*
*@paramnamescheduled的名稱(chēng)
*@paramfixedDelay上一次執(zhí)行完畢時(shí)間點(diǎn)之后多長(zhǎng)時(shí)間再執(zhí)行
*/
publicvoidsetScheduledFixedDelay(Stringname,LongfixedDelay){
//終止原先的任務(wù)
cancelScheduled(name);
//創(chuàng)建新的任務(wù)
ScheduledSourcescheduledSource=superScheduledConfig.getScheduledSource(name);
scheduledSource.clear();
scheduledSource.setFixedDelay(fixedDelay);
addScheduled(name,scheduledSource);
}

/**
*修改Scheduled的fixedRate
*
*@paramnamescheduled的名稱(chēng)
*@paramfixedRate上一次開(kāi)始執(zhí)行之后多長(zhǎng)時(shí)間再執(zhí)行
*/
publicvoidsetScheduledFixedRate(Stringname,LongfixedRate){
//終止原先的任務(wù)
cancelScheduled(name);
//創(chuàng)建新的任務(wù)
ScheduledSourcescheduledSource=superScheduledConfig.getScheduledSource(name);
scheduledSource.clear();
scheduledSource.setFixedRate(fixedRate);
addScheduled(name,scheduledSource);
}

/**
*查詢(xún)所有啟動(dòng)的Scheduled
*/
publicListgetRunScheduledName(){
Setnames=superScheduledConfig.getNameToScheduledFuture().keySet();
returnnewArrayList<>(names);
}

/**
*查詢(xún)所有的Scheduled
*/
publicListgetAllSuperScheduledName(){
Setnames=superScheduledConfig.getNameToRunnable().keySet();
returnnewArrayList<>(names);
}

/**
*終止Scheduled
*
*@paramnamescheduled的名稱(chēng)
*/
publicvoidcancelScheduled(Stringname){
ScheduledFuturescheduledFuture=superScheduledConfig.getScheduledFuture(name);
scheduledFuture.cancel(true);
superScheduledConfig.removeScheduledFuture(name);
logger.info(df.format(LocalDateTime.now())+"任務(wù)"+name+"已經(jīng)終止...");
}

/**
*啟動(dòng)Scheduled
*
*@paramnamescheduled的名稱(chēng)
*@paramscheduledSource定時(shí)任務(wù)的源信息
*/
publicvoidaddScheduled(Stringname,ScheduledSourcescheduledSource){
if(getRunScheduledName().contains(name)){
thrownewSuperScheduledException("定時(shí)任務(wù)"+name+"已經(jīng)被啟動(dòng)過(guò)了");
}
if(!scheduledSource.check()){
thrownewSuperScheduledException("定時(shí)任務(wù)"+name+"源數(shù)據(jù)內(nèi)容錯(cuò)誤");
}

scheduledSource.refreshType();

Runnablerunnable=superScheduledConfig.getRunnable(name);
ThreadPoolTaskSchedulertaskScheduler=superScheduledConfig.getTaskScheduler();


ScheduledFutureschedule=ScheduledFutureFactory.create(taskScheduler,scheduledSource,runnable);
logger.info(df.format(LocalDateTime.now())+"任務(wù)"+name+"已經(jīng)啟動(dòng)...");

superScheduledConfig.addScheduledSource(name,scheduledSource);
superScheduledConfig.addScheduledFuture(name,schedule);
}

/**
*以cron類(lèi)型啟動(dòng)Scheduled
*
*@paramnamescheduled的名稱(chēng)
*@paramcroncron表達(dá)式
*/
publicvoidaddCronScheduled(Stringname,Stringcron){
ScheduledSourcescheduledSource=newScheduledSource();
scheduledSource.setCron(cron);

addScheduled(name,scheduledSource);
}

/**
*以fixedDelay類(lèi)型啟動(dòng)Scheduled
*
*@paramnamescheduled的名稱(chēng)
*@paramfixedDelay上一次執(zhí)行完畢時(shí)間點(diǎn)之后多長(zhǎng)時(shí)間再執(zhí)行
*@paraminitialDelay第一次執(zhí)行的延遲時(shí)間
*/
publicvoidaddFixedDelayScheduled(Stringname,LongfixedDelay,Long...initialDelay){
ScheduledSourcescheduledSource=newScheduledSource();
scheduledSource.setFixedDelay(fixedDelay);
if(initialDelay!=null&&initialDelay.length==1){
scheduledSource.setInitialDelay(initialDelay[0]);
}elseif(initialDelay!=null&&initialDelay.length>1){
thrownewSuperScheduledException("第一次執(zhí)行的延遲時(shí)間只能傳入一個(gè)參數(shù)");
}

addScheduled(name,scheduledSource);
}

/**
*以fixedRate類(lèi)型啟動(dòng)Scheduled
*
*@paramnamescheduled的名稱(chēng)
*@paramfixedRate上一次開(kāi)始執(zhí)行之后多長(zhǎng)時(shí)間再執(zhí)行
*@paraminitialDelay第一次執(zhí)行的延遲時(shí)間
*/
publicvoidaddFixedRateScheduled(Stringname,LongfixedRate,Long...initialDelay){
ScheduledSourcescheduledSource=newScheduledSource();
scheduledSource.setFixedRate(fixedRate);
if(initialDelay!=null&&initialDelay.length==1){
scheduledSource.setInitialDelay(initialDelay[0]);
}elseif(initialDelay!=null&&initialDelay.length>1){
thrownewSuperScheduledException("第一次執(zhí)行的延遲時(shí)間只能傳入一個(gè)參數(shù)");
}

addScheduled(name,scheduledSource);
}

/**
*手動(dòng)執(zhí)行一次任務(wù)
*
*@paramnamescheduled的名稱(chēng)
*/
publicvoidrunScheduled(Stringname){
Runnablerunnable=superScheduledConfig.getRunnable(name);
runnable.run();
}
}

2、增強(qiáng)接口實(shí)現(xiàn)

增強(qiáng)器實(shí)現(xiàn)的整體思路與SpringAop的思路一致,實(shí)現(xiàn)沒(méi)有Aop復(fù)雜

(1) 增強(qiáng)接口

@Order(Ordered.HIGHEST_PRECEDENCE)
publicinterfaceBaseStrengthen{
/**
*前置強(qiáng)化方法
*
*@parambeanbean實(shí)例(或者是被代理的bean)
*@parammethod執(zhí)行的方法對(duì)象
*@paramargs方法參數(shù)
*/
voidbefore(Objectbean,Methodmethod,Object[]args);

/**
*后置強(qiáng)化方法
*出現(xiàn)異常不會(huì)執(zhí)行
*如果未出現(xiàn)異常,在afterFinally方法之后執(zhí)行
*
*@parambeanbean實(shí)例(或者是被代理的bean)
*@parammethod執(zhí)行的方法對(duì)象
*@paramargs方法參數(shù)
*/
voidafter(Objectbean,Methodmethod,Object[]args);

/**
*異常強(qiáng)化方法
*
*@parambeanbean實(shí)例(或者是被代理的bean)
*@parammethod執(zhí)行的方法對(duì)象
*@paramargs方法參數(shù)
*/
voidexception(Objectbean,Methodmethod,Object[]args);

/**
*Finally強(qiáng)化方法,出現(xiàn)異常也會(huì)執(zhí)行
*
*@parambeanbean實(shí)例(或者是被代理的bean)
*@parammethod執(zhí)行的方法對(duì)象
*@paramargs方法參數(shù)
*/
voidafterFinally(Objectbean,Methodmethod,Object[]args);
}

(2) 代理抽象類(lèi)

publicabstractclassPoint{
/**
*定時(shí)任務(wù)名
*/
privateStringsuperScheduledName;

/**
*抽象的執(zhí)行方法,使用代理實(shí)現(xiàn)
*@paramrunnable定時(shí)任務(wù)執(zhí)行器
*/
publicabstractObjectinvoke(SuperScheduledRunnablerunnable);

/*普通的get/sets省略*/
}

(3) 調(diào)用鏈類(lèi)

publicclassChain{
privateListlist;
privateintindex=-1;
/**
*索引自增1
*/
publicintincIndex(){
return++index;
}

/**
*索引還原
*/
publicvoidresetIndex(){
this.index=-1;
}
}

(4) cglib動(dòng)態(tài)代理實(shí)現(xiàn)

使用cglib代理增強(qiáng)器,將增強(qiáng)器全部代理成調(diào)用鏈節(jié)點(diǎn)Point

publicclassRunnableBaseInterceptorimplementsMethodInterceptor{
/**
*定時(shí)任務(wù)執(zhí)行器
*/
privateSuperScheduledRunnablerunnable;
/**
*定時(shí)任務(wù)增強(qiáng)類(lèi)
*/
privateBaseStrengthenstrengthen;

@Override
publicObjectintercept(Objectobj,Methodmethod,Object[]args,MethodProxymethodProxy)throwsThrowable{
Objectresult;
//如果執(zhí)行的是invoke()方法
if("invoke".equals(method.getName())){
//前置強(qiáng)化方法
strengthen.before(obj,method,args);
try{
//調(diào)用執(zhí)行器中的invoke()方法
result=runnable.invoke();
}catch(Exceptione){
//異常強(qiáng)化方法
strengthen.exception(obj,method,args);
thrownewSuperScheduledException(strengthen.getClass()+"中強(qiáng)化執(zhí)行時(shí)發(fā)生錯(cuò)誤",e);
}finally{
//Finally強(qiáng)化方法,出現(xiàn)異常也會(huì)執(zhí)行
strengthen.afterFinally(obj,method,args);
}
//后置強(qiáng)化方法
strengthen.after(obj,method,args);

}else{
//直接執(zhí)行方法
result=methodProxy.invokeSuper(obj,args);
}
returnresult;
}

publicRunnableBaseInterceptor(Objectobject,SuperScheduledRunnablerunnable){
this.runnable=runnable;
if(BaseStrengthen.class.isAssignableFrom(object.getClass())){
this.strengthen=(BaseStrengthen)object;
}else{
thrownewSuperScheduledException(object.getClass()+"對(duì)象不是BaseStrengthen類(lèi)型");
}
}

publicRunnableBaseInterceptor(){

}
}

(5) 定時(shí)任務(wù)執(zhí)行器實(shí)現(xiàn)

publicclassSuperScheduledRunnable{
/**
*原始的方法
*/
privateMethodmethod;
/**
*方法所在的bean
*/
privateObjectbean;
/**
*增強(qiáng)器的調(diào)用鏈
*/
privateChainchain;


publicObjectinvoke(){
Objectresult;
//索引自增1
if(chain.incIndex()==chain.getList().size()){
//調(diào)用鏈中的增強(qiáng)方法已經(jīng)全部執(zhí)行結(jié)束
try{
//調(diào)用鏈索引初始化
chain.resetIndex();
//增強(qiáng)器全部執(zhí)行完畢,執(zhí)行原本的方法
result=method.invoke(bean);
}catch(IllegalAccessException|InvocationTargetExceptione){
thrownewSuperScheduledException(e.getLocalizedMessage());
}
}else{
//獲取被代理后的方法增強(qiáng)器
Pointpoint=chain.getList().get(chain.getIndex());
//執(zhí)行增強(qiáng)器代理
//增強(qiáng)器代理中,會(huì)回調(diào)方法執(zhí)行器,形成調(diào)用鏈,逐一運(yùn)行調(diào)用鏈中的增強(qiáng)器
result=point.invoke(this);
}
returnresult;
}

/*普通的get/sets省略*/
}

(6) 增強(qiáng)器代理邏輯

com.gyx.superscheduled.core.SuperScheduledApplicationRunner類(lèi)中的代碼片段

//創(chuàng)建執(zhí)行控制器
SuperScheduledRunnablerunnable=newSuperScheduledRunnable();
runnable.setMethod(scheduledSource.getMethod());
runnable.setBean(scheduledSource.getBean());
//用來(lái)存放增強(qiáng)器的代理對(duì)象
Listpoints=newArrayList<>(baseStrengthenBeanNames.length);
//循環(huán)所有的增強(qiáng)器的beanName
for(StringbaseStrengthenBeanName:baseStrengthenBeanNames){
//獲取增強(qiáng)器的bean對(duì)象
ObjectbaseStrengthenBean=applicationContext.getBean(baseStrengthenBeanName);
//將增強(qiáng)器代理成Point節(jié)點(diǎn)
Pointproxy=ProxyUtils.getInstance(Point.class,newRunnableBaseInterceptor(baseStrengthenBean,runnable));
proxy.setSuperScheduledName(name);
//增強(qiáng)器的代理對(duì)象緩存到list中
points.add(proxy);
}
//將增強(qiáng)器代理實(shí)例的集合生成調(diào)用鏈
//執(zhí)行控制器中設(shè)置調(diào)用鏈
runnable.setChain(newChain(points));






審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀(guān)點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 處理器
    +關(guān)注

    關(guān)注

    68

    文章

    19286

    瀏覽量

    229842
  • 控制器
    +關(guān)注

    關(guān)注

    112

    文章

    16361

    瀏覽量

    178050
  • 增強(qiáng)器
    +關(guān)注

    關(guān)注

    1

    文章

    46

    瀏覽量

    8261
  • SpringBoot
    +關(guān)注

    關(guān)注

    0

    文章

    173

    瀏覽量

    179

原文標(biāo)題:SpringBoot 定時(shí)任務(wù)動(dòng)態(tài)管理通用解決方案

文章出處:【微信號(hào):AndroidPush,微信公眾號(hào):Android編程精選】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    【API】多pk分組&用戶(hù)場(chǎng)景&通用定時(shí)任務(wù)api已經(jīng)發(fā)布

    多PK分組、用戶(hù)場(chǎng)景和通用定時(shí)任務(wù)接口已經(jīng)發(fā)布。以上OPEN API 用戶(hù)/廠(chǎng)商 可免費(fèi)使用。多PK分組:可讓用戶(hù)/廠(chǎng)商對(duì)不用產(chǎn)品的設(shè)備進(jìn)行歸類(lèi)管理。接口兼容原有的單PK分組,不同點(diǎn)在于創(chuàng)建多 pk
    發(fā)表于 08-31 13:08

    Linux系統(tǒng)定時(shí)任務(wù)Crond

    Crond是linux系統(tǒng)中用來(lái)定期執(zhí)行命令/腳本或指定程序任務(wù)一種服務(wù)或軟件,般情況下,我們安裝完Centos5/6 linux操作系統(tǒng)之后,默認(rèn)便會(huì)啟動(dòng)Crond任務(wù)調(diào)度服務(wù)。
    發(fā)表于 07-05 06:22

    一種可網(wǎng)絡(luò)化管理和配置機(jī)頂盒的網(wǎng)絡(luò)解決方案

    一種可網(wǎng)絡(luò)化管理和配置機(jī)頂盒的網(wǎng)絡(luò)解決方案
    發(fā)表于 05-25 07:10

    SpringBoot如何實(shí)現(xiàn)動(dòng)態(tài)增刪啟停定時(shí)任務(wù)

    這兩方式不能動(dòng)態(tài)添加、刪除、啟動(dòng)、停止任務(wù)。 要實(shí)現(xiàn)動(dòng)態(tài)增刪啟停定時(shí)任務(wù)功能,比較廣泛的做法是集成Quartz框架。但是本人的開(kāi)發(fā)原則是:
    的頭像 發(fā)表于 09-24 09:49 ?2947次閱讀
    <b class='flag-5'>SpringBoot</b>如何實(shí)現(xiàn)<b class='flag-5'>動(dòng)態(tài)</b>增刪啟停<b class='flag-5'>定時(shí)任務(wù)</b>

    Python定時(shí)任務(wù)的實(shí)現(xiàn)方式

    在日常工作中,我們常常會(huì)用到需要周期性執(zhí)行的任務(wù)一種方式是采用 Linux 系統(tǒng)自帶的 crond 結(jié)合命令行實(shí)現(xiàn)。另外一種方式是直接使用Python。接下來(lái)整理的是常見(jiàn)的Python定時(shí)任
    的頭像 發(fā)表于 10-08 15:20 ?5733次閱讀

    如何在SpringBoot項(xiàng)目中實(shí)現(xiàn)動(dòng)態(tài)定時(shí)任務(wù)

    之前寫(xiě)過(guò)文章記錄怎么在SpringBoot項(xiàng)目中簡(jiǎn)單使用定時(shí)任務(wù),不過(guò)由于要借助cron表達(dá)式且都提前定義好放在配置文件里,不能在項(xiàng)目運(yùn)行中動(dòng)態(tài)修改任務(wù)執(zhí)行時(shí)間,實(shí)在不太靈活。
    的頭像 發(fā)表于 09-30 11:16 ?1813次閱讀

    說(shuō)說(shuō)Spring定時(shí)任務(wù)如何大規(guī)模企業(yè)級(jí)運(yùn)用

    定時(shí)任務(wù)是業(yè)務(wù)應(yīng)用開(kāi)發(fā)中非常普遍存在的場(chǎng)景(如:每分鐘掃描超時(shí)支付的訂單,每小時(shí)清理次數(shù)據(jù)庫(kù)歷史數(shù)據(jù),每天統(tǒng)計(jì)前天的數(shù)據(jù)并生成報(bào)表等等),解決方案很多,Spring 框架提供了
    的頭像 發(fā)表于 11-04 09:36 ?698次閱讀

    解析Golang定時(shí)任務(wù)庫(kù)gron設(shè)計(jì)和原理

    正巧,最近看到了 gron 這個(gè)開(kāi)源項(xiàng)目,它是用 Golang 實(shí)現(xiàn)個(gè)并發(fā)安全的定時(shí)任務(wù)庫(kù)。實(shí)現(xiàn)非常簡(jiǎn)單精巧,代碼量也不多。今天我們就來(lái)起結(jié)合源碼看下,怎樣基于 Golang 的
    的頭像 發(fā)表于 12-15 13:57 ?1339次閱讀

    SpringBoot如何實(shí)現(xiàn)定時(shí)任務(wù)(下)

    SpringBoot創(chuàng)建定時(shí)任務(wù)的方式很簡(jiǎn)單,主要有兩方式:、基于注解的方式(@Scheduled)二、數(shù)據(jù)庫(kù)動(dòng)態(tài)配置。實(shí)際開(kāi)發(fā)中,第
    的頭像 發(fā)表于 04-07 14:51 ?1237次閱讀
    <b class='flag-5'>SpringBoot</b>如何實(shí)現(xiàn)<b class='flag-5'>定時(shí)任務(wù)</b>(下)

    SpringBoot如何實(shí)現(xiàn)定時(shí)任務(wù)(上)

    SpringBoot創(chuàng)建定時(shí)任務(wù)的方式很簡(jiǎn)單,主要有兩方式:、基于注解的方式(@Scheduled)二、數(shù)據(jù)庫(kù)動(dòng)態(tài)配置。實(shí)際開(kāi)發(fā)中,第
    的頭像 發(fā)表于 04-07 14:51 ?1349次閱讀
    <b class='flag-5'>SpringBoot</b>如何實(shí)現(xiàn)<b class='flag-5'>定時(shí)任務(wù)</b>(上)

    Spring Boot中整合兩定時(shí)任務(wù)的方法

    在 Spring + SpringMVC 環(huán)境中,般來(lái)說(shuō),要實(shí)現(xiàn)定時(shí)任務(wù),我們有兩中方案一種是使用 Spring 自帶的定時(shí)任務(wù)處理器
    的頭像 發(fā)表于 04-07 14:55 ?1550次閱讀
    Spring Boot中整合兩<b class='flag-5'>種</b><b class='flag-5'>定時(shí)任務(wù)</b>的方法

    如何動(dòng)態(tài)添加修改刪除定時(shí)任務(wù)

    如何動(dòng)態(tài)添加修改刪除定時(shí)任務(wù)?那么我們起看看具體怎么實(shí)現(xiàn),先看下本節(jié)大綱: (1)思路說(shuō)明; (2)代碼解析; (3)修改定時(shí)任務(wù)執(zhí)行周期特別說(shuō)明;
    的頭像 發(fā)表于 04-12 11:06 ?1081次閱讀

    python定時(shí)任務(wù)實(shí)踐

    由于程序需求,監(jiān)測(cè)配置變化需要設(shè)置定時(shí)任務(wù),每分鐘執(zhí)行次,對(duì)任務(wù)持久化要求不高,不需要時(shí)可以關(guān)閉定時(shí)任務(wù)
    的頭像 發(fā)表于 05-20 17:53 ?977次閱讀
    python<b class='flag-5'>定時(shí)任務(wù)</b>實(shí)踐

    linux定時(shí)任務(wù)的用法總結(jié)

    習(xí)慣了使用 windows 的計(jì)劃任務(wù),使用 linux 中的 crontab 管理定時(shí)任務(wù)時(shí)很不適應(yīng)。
    的頭像 發(fā)表于 08-14 18:16 ?851次閱讀
    linux<b class='flag-5'>定時(shí)任務(wù)</b>的用法總結(jié)

    定時(shí)器技術(shù):Air780E如何革新定時(shí)任務(wù)管理

    今天講的是關(guān)于Air780E如何革新定時(shí)任務(wù)管理的內(nèi)容,希望大家有所收獲。
    的頭像 發(fā)表于 11-07 13:50 ?233次閱讀
    <b class='flag-5'>定時(shí)</b>器技術(shù):Air780E如何革新<b class='flag-5'>定時(shí)任務(wù)</b><b class='flag-5'>管理</b>?
    主站蜘蛛池模板: 日本三级日产三级国产三级| 免费艹逼视频| 在线亚洲精品| 亚洲成人在线免费观看| 久久99久久精品97久久综合| 午夜视频你懂的| 68日本xxxxxxxxx18能看的| 四虎免费在线播放| 不卡一级毛片免费高清| tube性欧美另类| 亚洲国产成人精品女人久久久 | 可以直接看的黄色网址| 午夜精品免费| 亚洲乱码一区二区三区在线观看| 三级在线观看国产| 美女被色| 久久国产免费观看| 一级毛片一级毛片一级毛片| 国产婷婷高清在线观看免费| 国产成人亚洲影视在线| 亚洲国产高清人在线| 成人av.com| 俺也啪| 人人看人人澡| 美女牲交视频一级毛片| 伊人久久99| bt天堂磁力搜索| 中国一级生活片| 你懂的在线视频观看| 久久国产精品系列| 婷婷亚洲视频| 五月天婷婷综合| 高清不卡一区| 成人在线天堂| 爽好舒服快受不了了老师| 久久久噜噜噜久久网| 成人精品综合免费视频| 色婷婷中文字幕| 欧美肉到失禁高h视频在线| 伊人毛片| www.亚洲视频.com|