1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        告別硬編碼,SpringBoot實(shí)現(xiàn)動(dòng)態(tài)增刪啟停定時(shí)任務(wù)!

        共 11849字,需瀏覽 24分鐘

         ·

        2021-10-13 07:19

        程序員的成長(zhǎng)之路
        互聯(lián)網(wǎng)/程序員/技術(shù)/資料共享?
        關(guān)注


        閱讀本文大概需要 6 分鐘。

        來(lái)自:jianshu.com/p/0f68936393fd

        在spring boot項(xiàng)目中,可以通過(guò)@EnableScheduling注解和@Scheduled注解實(shí)現(xiàn)定時(shí)任務(wù),也可以通過(guò)SchedulingConfigurer接口來(lái)實(shí)現(xiàn)定時(shí)任務(wù)。但是這兩種方式不能動(dòng)態(tài)添加、刪除、啟動(dòng)、停止任務(wù)。
        要實(shí)現(xiàn)動(dòng)態(tài)增刪啟停定時(shí)任務(wù)功能,比較廣泛的做法是集成Quartz框架。但是本人的開(kāi)發(fā)原則是:在滿足項(xiàng)目需求的情況下,盡量少的依賴其它框架,避免項(xiàng)目過(guò)于臃腫和復(fù)雜。
        查看spring-context這個(gè)jar包中org.springframework.scheduling.ScheduledTaskRegistrar這個(gè)類的源代碼,發(fā)現(xiàn)可以通過(guò)改造這個(gè)類就能實(shí)現(xiàn)動(dòng)態(tài)增刪啟停定時(shí)任務(wù)功能。
        定時(shí)任務(wù)列表頁(yè)
        定時(shí)任務(wù)執(zhí)行日志
        添加執(zhí)行定時(shí)任務(wù)的線程池配置類
        @Configuration??
        public?class?SchedulingConfig?{??
        ????@Bean??
        ????public?TaskScheduler?taskScheduler()?{??
        ????????ThreadPoolTaskScheduler?taskScheduler?=?new?ThreadPoolTaskScheduler();??
        ????????//?定時(shí)任務(wù)執(zhí)行線程池核心線程數(shù)??
        ????????taskScheduler.setPoolSize(4);??
        ????????taskScheduler.setRemoveOnCancelPolicy(true);??
        ????????taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");??
        ????????return?taskScheduler;??
        ????}??
        }??

        添加ScheduledFuture的包裝類。ScheduledFuture是ScheduledExecutorService定時(shí)任務(wù)線程池的執(zhí)行結(jié)果。
        public?final?class?ScheduledTask?{??
        ??
        ????volatile?ScheduledFuture?future;??
        ??
        ????/**??
        ?????*?取消定時(shí)任務(wù)??
        ?????*/??
        ????public?void?cancel()?{??
        ????????ScheduledFuture?future?=?this.future;??
        ????????if?(future?!=?null)?{??
        ????????????future.cancel(true);??
        ????????}??
        ????}??
        }??

        添加Runnable接口實(shí)現(xiàn)類,被定時(shí)任務(wù)線程池調(diào)用,用來(lái)執(zhí)行指定bean里面的方法。
        public?class?SchedulingRunnable?implements?Runnable?{??
        ??
        ????private?static?final?Logger?logger?=?LoggerFactory.getLogger(SchedulingRunnable.class);??
        ??
        ????private?String?beanName;??
        ??
        ????private?String?methodName;??
        ??
        ????private?String?params;??
        ??
        ????public?SchedulingRunnable(String?beanName,?String?methodName)?{??
        ????????this(beanName,?methodName,?null);??
        ????}??
        ??
        ????public?SchedulingRunnable(String?beanName,?String?methodName,?String?params)?{??
        ????????this.beanName?=?beanName;??
        ????????this.methodName?=?methodName;??
        ????????this.params?=?params;??
        ????}??
        ??
        ????@Override??
        ????public?void?run()?{??
        ????????logger.info("定時(shí)任務(wù)開(kāi)始執(zhí)行?- bean:{},方法:{},參數(shù):{}",?beanName,?methodName,?params);??
        ????????long?startTime?=?System.currentTimeMillis();??
        ??
        ????????try?{??
        ????????????Object?target?=?SpringContextUtils.getBean(beanName);??
        ??
        ????????????Method?method?=?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?(Exception?ex)?{??
        ????????????logger.error(String.format("定時(shí)任務(wù)執(zhí)行異常?- bean:%s,方法:%s,參數(shù):%s ",?beanName,?methodName,?params),?ex);??
        ????????}??
        ??
        ????????long?times?=?System.currentTimeMillis()?-?startTime;??
        ????????logger.info("定時(shí)任務(wù)執(zhí)行結(jié)束?- bean:{},方法:{},參數(shù):{},耗時(shí):{}?毫秒",?beanName,?methodName,?params,?times);??
        ????}??
        ??
        ????@Override??
        ????public?boolean?equals(Object?o)?{??
        ????????if?(this?==?o)?return?true;??
        ????????if?(o?==?null?||?getClass()?!=?o.getClass())?return?false;??
        ????????SchedulingRunnable?that?=?(SchedulingRunnable)?o;??
        ????????if?(params?==?null)?{??
        ????????????return?beanName.equals(that.beanName)?&&??
        ????????????????????methodName.equals(that.methodName)?&&??
        ????????????????????that.params?==?null;??
        ????????}??
        ??
        ????????return?beanName.equals(that.beanName)?&&??
        ????????????????methodName.equals(that.methodName)?&&??
        ????????????????params.equals(that.params);??
        ????}??
        ??
        ????@Override??
        ????public?int?hashCode()?{??
        ????????if?(params?==?null)?{??
        ????????????return?Objects.hash(beanName,?methodName);??
        ????????}??
        ??
        ????????return?Objects.hash(beanName,?methodName,?params);??
        ????}??
        }??

        添加定時(shí)任務(wù)注冊(cè)類,用來(lái)增加、刪除定時(shí)任務(wù)。
        @Component??
        public?class?CronTaskRegistrar?implements?DisposableBean?{??
        ??
        ????private?final?Map?scheduledTasks?=?new?ConcurrentHashMap<>(16);??
        ??
        ????@Autowired??
        ????private?TaskScheduler?taskScheduler;??
        ??
        ????public?TaskScheduler?getScheduler()?{??
        ????????return?this.taskScheduler;??
        ????}??
        ??
        ????public?void?addCronTask(Runnable?task,?String?cronExpression)?{??
        ????????addCronTask(new?CronTask(task,?cronExpression));??
        ????}??
        ??
        ????public?void?addCronTask(CronTask?cronTask)?{??
        ????????if?(cronTask?!=?null)?{??
        ????????????Runnable?task?=?cronTask.getRunnable();??
        ????????????if?(this.scheduledTasks.containsKey(task))?{??
        ????????????????removeCronTask(task);??
        ????????????}??
        ??
        ????????????this.scheduledTasks.put(task,?scheduleCronTask(cronTask));??
        ????????}??
        ????}??
        ??
        ????public?void?removeCronTask(Runnable?task)?{??
        ????????ScheduledTask?scheduledTask?=?this.scheduledTasks.remove(task);??
        ????????if?(scheduledTask?!=?null)??
        ????????????scheduledTask.cancel();??
        ????}??
        ??
        ????public?ScheduledTask?scheduleCronTask(CronTask?cronTask)?{??
        ????????ScheduledTask?scheduledTask?=?new?ScheduledTask();??
        ????????scheduledTask.future?=?this.taskScheduler.schedule(cronTask.getRunnable(),?cronTask.getTrigger());??
        ??
        ????????return?scheduledTask;??
        ????}??
        ??
        ??
        ????@Override??
        ????public?void?destroy()?{??
        ????????for?(ScheduledTask?task?:?this.scheduledTasks.values())?{??
        ????????????task.cancel();??
        ????????}??
        ??
        ????????this.scheduledTasks.clear();??
        ????}??
        }??

        添加定時(shí)任務(wù)示例類
        @Component("demoTask")??
        public?class?DemoTask?{??
        ????public?void?taskWithParams(String?params)?{??
        ????????System.out.println("執(zhí)行有參示例任務(wù):"?+?params);??
        ????}??
        ??
        ????public?void?taskNoParams()?{??
        ????????System.out.println("執(zhí)行無(wú)參示例任務(wù)");??
        ????}??
        }??

        定時(shí)任務(wù)數(shù)據(jù)庫(kù)表設(shè)計(jì)
        定時(shí)任務(wù)數(shù)據(jù)庫(kù)表設(shè)計(jì)
        添加定時(shí)任務(wù)實(shí)體類
        public?class?SysJobPO?{??
        ????/**??
        ?????*?任務(wù)ID??
        ?????*/??
        ????private?Integer?jobId;??
        ????/**??
        ?????*?bean名稱??
        ?????*/??
        ????private?String?beanName;??
        ????/**??
        ?????*?方法名稱??
        ?????*/??
        ????private?String?methodName;??
        ????/**??
        ?????*?方法參數(shù)??
        ?????*/??
        ????private?String?methodParams;??
        ????/**??
        ?????*?cron表達(dá)式??
        ?????*/??
        ????private?String?cronExpression;??
        ????/**??
        ?????*?狀態(tài)(1正常?0暫停)??
        ?????*/??
        ????private?Integer?jobStatus;??
        ????/**??
        ?????*?備注??
        ?????*/??
        ????private?String?remark;??
        ????/**??
        ?????*?創(chuàng)建時(shí)間??
        ?????*/??
        ????private?Date?createTime;??
        ????/**??
        ?????*?更新時(shí)間??
        ?????*/??
        ????private?Date?updateTime;??
        ??
        ????public?Integer?getJobId()?{??
        ????????return?jobId;??
        ????}??
        ??
        ????public?void?setJobId(Integer?jobId)?{??
        ????????this.jobId?=?jobId;??
        ????}??
        ??
        ????public?String?getBeanName()?{??
        ????????return?beanName;??
        ????}??
        ??
        ????public?void?setBeanName(String?beanName)?{??
        ????????this.beanName?=?beanName;??
        ????}??
        ??
        ????public?String?getMethodName()?{??
        ????????return?methodName;??
        ????}??
        ??
        ????public?void?setMethodName(String?methodName)?{??
        ????????this.methodName?=?methodName;??
        ????}??
        ??
        ????public?String?getMethodParams()?{??
        ????????return?methodParams;??
        ????}??
        ??
        ????public?void?setMethodParams(String?methodParams)?{??
        ????????this.methodParams?=?methodParams;??
        ????}??
        ??
        ????public?String?getCronExpression()?{??
        ????????return?cronExpression;??
        ????}??
        ??
        ????public?void?setCronExpression(String?cronExpression)?{??
        ????????this.cronExpression?=?cronExpression;??
        ????}??
        ??
        ????public?Integer?getJobStatus()?{??
        ????????return?jobStatus;??
        ????}??
        ??
        ????public?void?setJobStatus(Integer?jobStatus)?{??
        ????????this.jobStatus?=?jobStatus;??
        ????}??
        ??
        ????public?String?getRemark()?{??
        ????????return?remark;??
        ????}??
        ??
        ????public?void?setRemark(String?remark)?{??
        ????????this.remark?=?remark;??
        ????}??
        ??
        ????public?Date?getCreateTime()?{??
        ????????return?createTime;??
        ????}??
        ??
        ????public?void?setCreateTime(Date?createTime)?{??
        ????????this.createTime?=?createTime;??
        ????}??
        ??
        ????public?Date?getUpdateTime()?{??
        ????????return?updateTime;??
        ????}??
        ??
        ????public?void?setUpdateTime(Date?updateTime)?{??
        ????????this.updateTime?=?updateTime;??
        ????}??
        ??
        }??

        新增定時(shí)任務(wù)
        新增定時(shí)任務(wù)
        boolean?success?=?sysJobRepository.addSysJob(sysJob);??
        if?(!success)??
        ????return?OperationResUtils.fail("新增失敗");??
        else?{??
        ????if?(sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{??
        ????????SchedulingRunnable?task?=?new?SchedulingRunnable(sysJob.getBeanName(),?sysJob.getMethodName(),?sysJob.getMethodParams());??
        ????????cronTaskRegistrar.addCronTask(task,?sysJob.getCronExpression());??
        ????}??
        }??
        ??
        return?OperationResUtils.success();??

        修改定時(shí)任務(wù),先移除原來(lái)的任務(wù),再啟動(dòng)新任務(wù)
        boolean?success?=?sysJobRepository.editSysJob(sysJob);??
        if?(!success)??
        ????return?OperationResUtils.fail("編輯失敗");??
        else?{??
        ????//先移除再添加??
        ????if?(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{??
        ????????SchedulingRunnable?task?=?new?SchedulingRunnable(existedSysJob.getBeanName(),?existedSysJob.getMethodName(),?existedSysJob.getMethodParams());??
        ????????cronTaskRegistrar.removeCronTask(task);??
        ????}??
        ??
        ????if?(sysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{??
        ????????SchedulingRunnable?task?=?new?SchedulingRunnable(sysJob.getBeanName(),?sysJob.getMethodName(),?sysJob.getMethodParams());??
        ????????cronTaskRegistrar.addCronTask(task,?sysJob.getCronExpression());??
        ????}??
        }??
        ??
        return?OperationResUtils.success();??

        刪除定時(shí)任務(wù)
        boolean?success?=?sysJobRepository.deleteSysJobById(req.getJobId());??
        if?(!success)??
        ????return?OperationResUtils.fail("刪除失敗");??
        else{??
        ????if?(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{??
        ????????SchedulingRunnable?task?=?new?SchedulingRunnable(existedSysJob.getBeanName(),?existedSysJob.getMethodName(),?existedSysJob.getMethodParams());??
        ????????cronTaskRegistrar.removeCronTask(task);??
        ????}??
        }??
        ??
        return?OperationResUtils.success();??

        定時(shí)任務(wù)啟動(dòng)/停止?fàn)顟B(tài)切換
        if?(existedSysJob.getJobStatus().equals(SysJobStatus.NORMAL.ordinal()))?{??
        ????SchedulingRunnable?task?=?new?SchedulingRunnable(existedSysJob.getBeanName(),?existedSysJob.getMethodName(),?existedSysJob.getMethodParams());??
        ????cronTaskRegistrar.addCronTask(task,?existedSysJob.getCronExpression());??
        }?else?{??
        ????SchedulingRunnable?task?=?new?SchedulingRunnable(existedSysJob.getBeanName(),?existedSysJob.getMethodName(),?existedSysJob.getMethodParams());??
        ????cronTaskRegistrar.removeCronTask(task);??
        }??

        添加實(shí)現(xiàn)了CommandLineRunner接口的SysJobRunner類,當(dāng)spring boot項(xiàng)目啟動(dòng)完成后,加載數(shù)據(jù)庫(kù)里狀態(tài)為正常的定時(shí)任務(wù)。
        @Service??
        public?class?SysJobRunner?implements?CommandLineRunner?{??
        ??
        ????private?static?final?Logger?logger?=?LoggerFactory.getLogger(SysJobRunner.class);??
        ??
        ????@Autowired??
        ????private?ISysJobRepository?sysJobRepository;??
        ??
        ????@Autowired??
        ????private?CronTaskRegistrar?cronTaskRegistrar;??
        ??
        ????@Override??
        ????public?void?run(String...?args)?{??
        ????????//?初始加載數(shù)據(jù)庫(kù)里狀態(tài)為正常的定時(shí)任務(wù)??
        ????????List?jobList?=?sysJobRepository.getSysJobListByStatus(SysJobStatus.NORMAL.ordinal());??
        ????????if?(CollectionUtils.isNotEmpty(jobList))?{??
        ????????????for?(SysJobPO?job?:?jobList)?{??
        ????????????????SchedulingRunnable?task?=?new?SchedulingRunnable(job.getBeanName(),?job.getMethodName(),?job.getMethodParams());??
        ????????????????cronTaskRegistrar.addCronTask(task,?job.getCronExpression());??
        ????????????}??
        ??
        ????????????logger.info("定時(shí)任務(wù)已加載完畢...");??
        ????????}??
        ????}??
        }??

        工具類SpringContextUtils,用來(lái)從spring容器里獲取bean
        @Component??
        public?class?SpringContextUtils?implements?ApplicationContextAware?{??
        ??
        ????private?static?ApplicationContext?applicationContext;??
        ??
        ????@Override??
        ????public?void?setApplicationContext(ApplicationContext?applicationContext)??
        ????????????throws?BeansException?{??
        ????????SpringContextUtils.applicationContext?=?applicationContext;??
        ????}??
        ??
        ????public?static?Object?getBean(String?name)?{??
        ????????return?applicationContext.getBean(name);??
        ????}??
        ??
        ????public?static??T?getBean(Class?requiredType)?{??
        ????????return?applicationContext.getBean(requiredType);??
        ????}??
        ??
        ????public?static??T?getBean(String?name,?Class?requiredType)?{??
        ????????return?applicationContext.getBean(name,?requiredType);??
        ????}??
        ??
        ????public?static?boolean?containsBean(String?name)?{??
        ????????return?applicationContext.containsBean(name);??
        ????}??
        ??
        ????public?static?boolean?isSingleton(String?name)?{??
        ????????return?applicationContext.isSingleton(name);??
        ????}??
        ??
        ????public?static?Class?getType(String?name)?{??
        ????????return?applicationContext.getType(name);??
        ????}??
        }

        本文完,參考本文代碼可成功運(yùn)行,親測(cè)!

        推薦閱讀:

        0.2秒居然復(fù)制了100G文件?

        SpringBoot + Kafka + ELK 完成海量日志收集(超詳細(xì))

        互聯(lián)網(wǎng)初中高級(jí)大廠面試題(9個(gè)G)

        內(nèi)容包含Java基礎(chǔ)、JavaWeb、MySQL性能優(yōu)化、JVM、鎖、百萬(wàn)并發(fā)、消息隊(duì)列、高性能緩存、反射、Spring全家桶原理、微服務(wù)、Zookeeper、數(shù)據(jù)結(jié)構(gòu)、限流熔斷降級(jí)......等技術(shù)棧!

        ?戳閱讀原文領(lǐng)??!? ? ? ? ? ? ? ??? ??? ? ? ? ? ? ? ? ? ?朕已閱?

        瀏覽 50
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        評(píng)論
        圖片
        表情
        推薦
        點(diǎn)贊
        評(píng)論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            欧美激情999 | 国产视频aaa | 久久三级片电影 | 扒开腿灌牛奶调教赵丽颖 | 精品无码一区二区三区免费 | 日日夜夜狠狠爱 | 美女做爱网站免费视频 | 乡村美女户外勾搭av | 男男无遮挡啪啪 | 日逼www |