SpringBoot定时任务动态扩展ScheduledTaskRegistrar

这篇具有很好参考价值的文章主要介绍了SpringBoot定时任务动态扩展ScheduledTaskRegistrar。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

摘要:本文主要介绍基于SpringBoot定时任务ScheduledTaskRegistrar的动态扩展,实现定时任务的动态新增和删除。

ScheduledTaskRegistrar类简要描述

平常使用方式配置

  • Application启动类上添加注解@EnableScheduling
@EnableScheduling
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
复制代码
  • 在需要定时的方法上添加定时注解@Scheduled(cron = "0/10 * * * * ?")
@Slf4j
@Component
public class OtherScheduler {

    @Scheduled(cron = "0/10 * * * * ?")
    public void print(){
        log.info("每10S打印一次");
    }

    @Scheduled(cron = "0/5 * * * * ?")
    public void print5(){
        log.info("每5S打印一次");
    }

}
复制代码

原理分析

默认的方式启动把ScheduledAnnotationBeanPostProcessor该类实例化到SpringBootBean管理中,并且该类持有一个ScheduledTaskRegistrar属性,然后扫描出来拥有@Scheduled注解的方法,添加到定时任务中。

  • 添加定时任务到列表中

扫描到@Scheduled注解的时候调用了该方法添加任务

public void addCronTask(Runnable task, String expression) {
	if (!CRON_DISABLED.equals(expression)) {
		addCronTask(new CronTask(task, expression));
	}
}
复制代码
  • 启动定时任务

在对象实例化完成后,调用了afterPropertiesSet方法,该方法实际使用中执行了

public void afterPropertiesSet() {
	scheduleTasks();
}

protected void scheduleTasks() {
	if (this.taskScheduler == null) {
		this.localExecutor = Executors.newSingleThreadScheduledExecutor();
		this.taskScheduler = new ConcurrentTaskScheduler(this.localExecutor);
	}
	if (this.triggerTasks != null) {
		for (TriggerTask task : this.triggerTasks) {
			addScheduledTask(scheduleTriggerTask(task));
		}
	}
	if (this.cronTasks != null) {
		for (CronTask task : this.cronTasks) {
			addScheduledTask(scheduleCronTask(task));
		}
	}
	if (this.fixedRateTasks != null) {
		for (IntervalTask task : this.fixedRateTasks) {
			addScheduledTask(scheduleFixedRateTask(task));
		}
	}
	if (this.fixedDelayTasks != null) {
		for (IntervalTask task : this.fixedDelayTasks) {
			addScheduledTask(scheduleFixedDelayTask(task));
		}
	}
}

private void addScheduledTask(@Nullable ScheduledTask task) {
	if (task != null) {
		this.scheduledTasks.add(task);
	}
}

// 启动任务核心方法
public ScheduledTask scheduleCronTask(CronTask task) {
	ScheduledTask scheduledTask = this.unresolvedTasks.remove(task);
	boolean newTask = false;
	if (scheduledTask == null) {
		scheduledTask = new ScheduledTask(task);
		newTask = true;
	}
	if (this.taskScheduler != null) {
		scheduledTask.future = this.taskScheduler.schedule(task.getRunnable(), task.getTrigger());
	}
	else {
		addCronTask(task);
		this.unresolvedTasks.put(task, scheduledTask);
	}
	return (newTask ? scheduledTask : null);
}
复制代码

DynamicScheduledTaskRegistrar动态任务注册类

下面改动主要涉及到线程池数量、新增任务、删除任务、销毁任务四个方面;

public class DynamicScheduledTaskRegistrar extends ScheduledTaskRegistrar {

    private static final Logger log = LoggerFactory.getLogger(DynamicScheduledTaskRegistrar.class);

    private final Map<String,ScheduledTask> scheduledTaskMap = new LinkedHashMap<>(16);

    public DynamicScheduledTaskRegistrar(){
        super();
        // 两种实现方案
        //ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(10);
        //TaskScheduler taskScheduler = new ConcurrentTaskScheduler(scheduledExecutorService);
        // 第二种实现方案
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        taskScheduler.setPoolSize(8);
        taskScheduler.setRemoveOnCancelPolicy(true);
        taskScheduler.setThreadNamePrefix("dynamic-scheduled-task-");
        taskScheduler.initialize();
        this.setScheduler(taskScheduler);
    }
    /**
     * 新增任务
     * @param taskName
     * @param cron
     * @param runnable
     */
    public Boolean addCronTask(String taskName,String cron,Runnable runnable){
        if(scheduledTaskMap.containsKey(taskName)){
            log.error("定时任务["+ taskName+"]已存在,添加失败");
            return Boolean.FALSE;
        }
        CronTask cronTask = new CronTask(runnable,cron);
        ScheduledTask scheduledTask = this.scheduleCronTask(cronTask);
        scheduledTaskMap.put(taskName,scheduledTask);
        log.info("定时任务["+taskName+"]新增成功");
        return Boolean.TRUE;
    }

    /**
     * 删除任务
     * @param taskName
     */
    public void cancelCronTask(String taskName){
        ScheduledTask scheduledTask = scheduledTaskMap.get(taskName);
        if(null != scheduledTask){
            scheduledTask.cancel();
            scheduledTaskMap.remove(taskName);
        }
        log.info("定时任务["+taskName+"]删除成功");
    }

    @Override
    public void destroy() {
        super.destroy();
        scheduledTaskMap.values().forEach(ScheduledTask::cancel);
    }
}
复制代码

线程池数量问题

由于默认是单线程的,如果任务阻塞时间过长则会导致后续的任务阻塞,所以尽量是异步任务或者是线程池数量大一点,则可以避免这个问题

DynamicScheduledTaskService

@Service
public class DynamicScheduledTaskService {

    private static final Logger log = LoggerFactory.getLogger(DynamicScheduledTaskService.class);

    private final DynamicScheduledTaskRegistrar dynamicScheduledTaskRegistrar = new DynamicScheduledTaskRegistrar();

    /**
     * 新增任务
     * @param taskName
     * @param cron
     */
    public void add(String taskName,String cron){
        Boolean result = dynamicScheduledTaskRegistrar.addCronTask(taskName,cron,() -> print(taskName));
        log.info("定时任务添加结果:" + result);
    }

    /**
     * 取消任务
     * @param taskName
     */
    public void cancel(String taskName){
        dynamicScheduledTaskRegistrar.cancelCronTask(taskName);
    }

    private void print(String taskName){
        log.info(taskName+"开始");
        try{
            Thread.sleep(9000L);
            log.info(taskName+"结束111");
        }catch (Exception ex){

        }
        log.info(taskName+"结束");
    }

}
复制代码

SchedulerController

@RestController
@RequestMapping(value = "scheduler")
public class SchedulerController {

    @Autowired
    private DynamicScheduledTaskService dynamicScheduledTaskService;

    @GetMapping(value = "add")
    public Object add(String taskName,String cron){
        dynamicScheduledTaskService.add(taskName,cron);
        return "SUCCESS";
    }

    @GetMapping(value = "cancel")
    public Object cancel(String jobName){
        dynamicScheduledTaskService.cancel(jobName);
        return "SUCCESS";
    }

}
复制代码

测试结果

新增的任务都睡眠了9S

新增调度任务

SpringBoot定时任务动态扩展ScheduledTaskRegistrar

SpringBoot定时任务动态扩展ScheduledTaskRegistrar

删除调度任务

SpringBoot定时任务动态扩展ScheduledTaskRegistrar

SpringBoot定时任务动态扩展ScheduledTaskRegistrar文章来源地址https://www.toymoban.com/news/detail-427339.html

到了这里,关于SpringBoot定时任务动态扩展ScheduledTaskRegistrar的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • xxl-job定时任务配置应用以及添加到自己已有的springboot项目中实现动态API调用

    XXL-JOB是一个分布式任务调度平台,其核心设计目标是开发迅速、学习简单、轻量级、易扩展。现已开放源代码并接入多家公司线上产品线,开箱即用。 本篇文章主要是对xuxueli的xxl-job做一个简单的配置,以及将其添加到自己已有的项目中进行api调用。 一、xxl-job安装 1、首先

    2024年02月03日
    浏览(39)
  • springboot定时任务:同时使用定时任务和websocket报错

    项目使用了websocket,实现了消息的实时推送。后来项目需要一个定时任务,使用org.springframework.scheduling.annotation的@EnableScheduling注解来实现,启动项目之后报错 打断点 进入代码发现是这个定时任务的bean为null 由于先写的websocket推送消息,运行正常。之前一个项目只有一个定时任

    2024年02月11日
    浏览(36)
  • springboot 与异步任务,定时任务,邮件任务

    在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的;但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在Spring 3.x之后,就已经内置了@Async来完美解决这个问题。 SpringBoot 实现比较简单 主启

    2024年02月10日
    浏览(39)
  • Quartz实战:基于Quartz实现定时任务的动态调度,实现定时任务的增删改查

    Quartz使用文档,使用Quartz实现动态任务,Spring集成Quartz,Quartz集群部署,Quartz源码分析 Quartz使用文档,使用Quartz实现动态任务,Spring集成Quartz,Quartz集群部署,Quartz源码分析 此处省略了SysJob实体类,以及Mapper等对数据库的操作。 本文只是大致实现一个基于Quartz实现定时任务

    2024年02月15日
    浏览(47)
  • 【springboot】springboot定时任务:

    一、文档: 【cron表达式在线生成器】https://cron.qqe2.com/ 二、案例:

    2024年02月11日
    浏览(45)
  • Spring Boot动态设置定时任务

            spring boot项目实现定时任务,最简单的一种就是基于注解 @Schedule 的方式,在启动类上添加 @EnableScheduling 注解进行标注,就可实现。但是,这个方式有个缺点,那就是执行周期写死在代码里,无法动态改变,想要改变只能修改代码再重新部署启动。为了能够动态的

    2024年02月08日
    浏览(46)
  • springboot---定时任务实现

    任意类中创建一个方法,将该方法用@scheduled注解修饰,然后在项目的主方法上添加@EnableScheduling注解,定时任务就会生效。 但是需要注意的是定时任务不会一开始就执行,会等待设定的时间 1.2.1. cron cron表达式是一个字符串,字符串以5或6个空格隔开,分开共6或7个域,每一个

    2024年02月11日
    浏览(38)
  • SpringBoot——Scheduled定时任务

    目录 1.静态定时任务 2.动态定时任务 在一些业务场景中,我们需要定义一些任务在我们指定的时间或是每隔一个时间段就自动执行,来作为任务的前提,保证业务的执行。比如:我们需要一个定时任务,每天早上6点执行,对数据库中的某个日期字段进行修改,修改为当天时

    2023年04月17日
    浏览(36)
  • SpringBoot 实现定时任务

    定时任务在实际项目开发中很常见,并且定时任务可以在各种场景中应用,通过自动化操作和任务的规模化管理,提高效率、可靠性和工作质量。可以减少手动操作,避免疏忽和错误,并节省时间和人力资源的投入 简单易用: 使用注解驱动的方式,简化了定时任务的配置和

    2024年02月12日
    浏览(56)
  • SpringBoot——Quartz 定时任务

    优质博文:IT-BLOG-CN 【1】添加 Scheduled 相关依赖,它是 Spring 自带的一个 jar 包因此引入 Spring 的依赖: 【2】导入依赖之后,就可以在 Maven Dependencies 中看到相关的依赖,如下: 【3】编写定时任务类:重点是 @Scheduled 注解和 cron 属性; 【4】在启动类中开启定时任务的启动:

    2024年02月05日
    浏览(42)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包