700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > @scheduled cron动态修改_spring boot实现动态增删启停定时任务

@scheduled cron动态修改_spring boot实现动态增删启停定时任务

时间:2023-11-19 22:29:00

相关推荐

@scheduled cron动态修改_spring boot实现动态增删启停定时任务

作者:jessehua

来源:/p/0f68936393fd

在spring boot项目中,可以通过@EnableScheduling注解和@Scheduled注解实现定时任务,也可以通过SchedulingConfigurer接口来实现定时任务。但是这两种方式不能动态添加、删除、启动、停止任务。要实现动态增删启停定时任务功能,比较广泛的做法是集成Quartz框架。但是本人的开发原则是:在满足项目需求的情况下,尽量少的依赖其它框架,避免项目过于臃肿和复杂。查看spring-context这个jar包中org.springframework.scheduling.ScheduledTaskRegistrar这个类的源代码,发现可以通过改造这个类就能实现动态增删启停定时任务功能。

img

定时任务列表页

img

定时任务执行日志

添加执行定时任务的线程池配置类

@Configuration

publicclassSchedulingConfig{

@Bean

publicTaskSchedulertaskScheduler(){

ThreadPoolTaskSchedulertaskScheduler=newThreadPoolTaskScheduler();

//定时任务执行线程池核心线程数

taskScheduler.setPoolSize(4);

taskScheduler.setRemoveOnCancelPolicy(true);

taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");

returntaskScheduler;

}

}

添加ScheduledFuture的包装类。ScheduledFuture是ScheduledExecutorService定时任务线程池的执行结果。

publicfinalclassScheduledTask{

volatileScheduledFuture>future;

/**

*取消定时任务

*/

publicvoidcancel(){

ScheduledFuture>future=this.future;

if(future!=null){

future.cancel(true);

}

}

}

添加Runnable接口实现类,被定时任务线程池调用,用来执行指定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("定时任务开始执行- bean:{},方法:{},参数:{}",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("定时任务执行异常- bean:%s,方法:%s,参数:%s ",beanName,methodName,params),ex);

}

longtimes=System.currentTimeMillis()-startTime;

logger.info("定时任务执行结束- bean:{},方法:{},参数:{},耗时:{}毫秒",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);

}

}

添加定时任务注册类,用来增加、删除定时任务。

@Component

publicclassCronTaskRegistrarimplementsDisposableBean{

privatefinalMapscheduledTasks=newConcurrentHashMap<>(16);@AutowiredprivateTaskSchedulertaskScheduler;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;

}@Overridepublicvoiddestroy(){for(ScheduledTasktask:this.scheduledTasks.values()){

task.cancel();

}this.scheduledTasks.clear();

}

}

添加定时任务示例类

@Component("demoTask")

publicclassDemoTask{

publicvoidtaskWithParams(Stringparams){

System.out.println("执行有参示例任务:"+params);

}

publicvoidtaskNoParams(){

System.out.println("执行无参示例任务");

}

}

定时任务数据库表设计

img

定时任务数据库表设计

添加定时任务实体类

publicclassSysJobPO{

/**

*任务ID

*/

privateIntegerjobId;

/**

*bean名称

*/

privateStringbeanName;

/**

*方法名称

*/

privateStringmethodName;

/**

*方法参数

*/

privateStringmethodParams;

/**

*cron表达式

*/

privateStringcronExpression;

/**

*状态(1正常0暂停)

*/

privateIntegerjobStatus;

/**

*备注

*/

privateStringremark;

/**

*创建时间

*/

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;

}

}

新增定时任务

img

新增定时任务

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();

修改定时任务,先移除原来的任务,再启动新任务

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();

删除定时任务

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();

定时任务启动/停止状态切换

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);

}

添加实现了CommandLineRunner接口的SysJobRunner类,当spring boot项目启动完成后,加载数据库里状态为正常的定时任务。

@Service

publicclassSysJobRunnerimplementsCommandLineRunner{

privatestaticfinalLoggerlogger=LoggerFactory.getLogger(SysJobRunner.class);

@Autowired

privateISysJobRepositorysysJobRepository;

@Autowired

privateCronTaskRegistrarcronTaskRegistrar;

@Override

publicvoidrun(String...args){

//初始加载数据库里状态为正常的定时任务

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("定时任务已加载完毕...");

}

}

}

工具类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);

}publicstaticClassextendsObject>getType(Stringname){returnapplicationContext.getType(name);

}

}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。