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日
    浏览(40)
  • springboot定时任务:同时使用定时任务和websocket报错

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

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

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

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

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

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

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

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

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

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

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

    2024年02月05日
    浏览(43)
  • [SpringBoot系列] 定时任务

    假设我们已经搭建好了一个基于Spring Boot项目,首先我们要在Application中设置启用定时任务功能@EnableScheduling 启动定时任务 其中 @EnableScheduling 注解的作用是发现注解@Scheduled的任务并后台执行。 定时任务具体实现类 接下来我们来创建一个定时任务 运行Spring Boot,输出结果为如

    2023年04月20日
    浏览(75)
  • springboot---定时任务实现

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

    2024年02月11日
    浏览(39)
  • springboot:定时任务

    目录 一、实现定时任务的方法一:基于JDK 方法一:使用JDK自带的Timer类 法二:使用ScheduleExecutorsService类 二、基于Spring Task实现定时任务(推荐使用)  三、基于Quartz实现定时调度 四、使用分布式定时任务框架:elastic-job 五、分布式任务调度:国产组件XXL-Job 定时任务在项目中的

    2024年02月16日
    浏览(55)

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

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

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

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

二维码1

领取红包

二维码2

领红包