SpringBoot 动态操作定时任务(启动、停止、修改执行周期)

springboot自身带有一套定时任务框架,使用起来也比较简单,只需要在应用上添加@EnableScheduling注解开启定时任务的支持,然后在具体任务实现的方法上添加 @Scheduled然后配置corn表达式就完成了。

代码示例:

1、开启定时任务的支持
package com.syx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
@EnableScheduling
public class MainApp {
    public static void main(String[] args) {
        SpringApplication.run(MainApp.class,args);
    }
}

2、任务方法上添加@Scheduled注解

package com.syx.task;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronSequenceGenerator;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.scheduling.support.SimpleTriggerContext;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.TimeZone;

@Component
public class SayHelloTask {

    @Scheduled(cron = "0/50 * * * *  ?")
    public void sayHello() {
        System.out.println("hello2222 ...");

        //用于计算下次任务的执行时间
        CronTrigger cronTrigger = new CronTrigger("0/50 * * * *  ?");
        Date nextFireTime = cronTrigger.nextExecutionTime(new SimpleTriggerContext());
        System.out.println("任务下次的执行时间>>>"+nextFireTime);
    }
}

其中CronTrigger类可用于解析corn表达式,并且可以计算任务的下次触发时间。

通过上述的例子我们发现,这个任务的执行时间都是写死的,一旦应用启动后任务就会按照指定的corn表达式进行运行,如果我们想关闭或者修改任务的触发时间就需要停止应用修改代码,非常不方便缺乏灵活性,所以我们需要设计一套可以使用外部指令在不关闭应用的情况下对定时任务进行控制。

实现方案:

** 使用springboot提供的ThreadPoolTaskScheduler类进行任务的提交,然后发送http控制指令就可以实现该功能。**

代码示例:

1、配置ThreadPoolTaskScheduler

package com.syx.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
public class ScheduledConfig {
    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(3);
        threadPoolTaskScheduler.setRemoveOnCancelPolicy(true);
        return threadPoolTaskScheduler;
    }
}

2、任务控制controller

package com.syx.controller;

import com.syx.entity.ScheduledFutureHolder;
import com.syx.task.HelloTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.concurrent.ScheduledFuture;

@RestController
public class DoScheduledController {
    @Autowired
    private ThreadPoolTaskScheduler threadPoolTaskScheduler;

    //存储任务执行的包装类
    private HashMap<String, ScheduledFutureHolder> scheduleMap = new HashMap<>();

    /**
     *启动任务 
     * 如果不想手动触发任务可以使用 @PostConstruct注解来启动
     */
    @RequestMapping("/start")
    public void startTask()  {
        try {
            //初始化一个任务(这里可以初始话多个)  
            HelloTask helloTask = new HelloTask();
            String corn = "0/2 * * * *  ?";
            //将任务交给任务调度器执行
            ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(helloTask, new CronTrigger(corn));

            //将任务包装成ScheduledFutureHolder
            ScheduledFutureHolder scheduledFutureHolder = new ScheduledFutureHolder();
            scheduledFutureHolder.setScheduledFuture(schedule);
            scheduledFutureHolder.setRunnableClass(helloTask.getClass());
            scheduledFutureHolder.setCorn(corn);

            scheduleMap.put(scheduledFutureHolder.getRunnableClass().getName(),scheduledFutureHolder);
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 查询所有的任务
     */
    @RequestMapping("/queryTask")
    public void queryTask(){
        scheduleMap.forEach((k,v)->{
            System.out.println(k+"  "+v);
        });
    }

    /**
     * 停止任务
     * @param className
     */
    @RequestMapping("/stop/{className}")
    public void stopTask(@PathVariable  String className){
        if(scheduleMap.containsKey(className)){//如果包含这个任务
            ScheduledFuture<?> scheduledFuture = scheduleMap.get(className).getScheduledFuture();
            if(scheduledFuture!=null){
                scheduledFuture.cancel(true);
            }
        }
    }


    /**
     * 重启任务,修改任务的触发时间
     * @param className
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    @RequestMapping("/restart/{className}")
    public void restartTask(@PathVariable String className) throws InstantiationException, IllegalAccessException {
        if(scheduleMap.containsKey(className)){//如果包含这个任务


            //这里的corn可以通过前端动态传过来
            String corn = "0/50 * * * *  ?";
            ScheduledFutureHolder scheduledFutureHolder = scheduleMap.get(className);
            ScheduledFuture<?> scheduledFuture = scheduledFutureHolder.getScheduledFuture();
            if(scheduledFuture!=null){
                //先停掉任务
                scheduledFuture.cancel(true);

                //修改触发时间重新启动任务
                Runnable runnable = scheduledFutureHolder.getRunnableClass().newInstance();

                ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(runnable, new CronTrigger(corn));

                scheduledFutureHolder.setScheduledFuture(schedule);
                scheduledFutureHolder.setCorn(corn);

                scheduleMap.put(scheduledFutureHolder.getRunnableClass().getName(),scheduledFutureHolder);
            }
        }
    }
}

3、实现需求的具体任务(必须实现runnable接口,threadPoolTaskScheduler需要接受一个runnable的实现类)

package com.syx.task;
public class HelloTask implements Runnable{
    @Override
    public void run() {
        System.out.println("hello world");
    }
}

4、ScheduledFutureHolder自定义的一个辅助类,对任务执行进行包装

package com.syx.entity;

import java.util.concurrent.ScheduledFuture;

/**
 * 任务执行的包装类
 */
public class ScheduledFutureHolder {
    private ScheduledFuture<?> scheduledFuture;

    private Class<? extends Runnable> runnableClass;

    private String corn;

    public ScheduledFuture<?> getScheduledFuture() {
        return scheduledFuture;
    }

    public void setScheduledFuture(ScheduledFuture<?> scheduledFuture) {
        this.scheduledFuture = scheduledFuture;
    }

    public Class<? extends Runnable> getRunnableClass() {
        return runnableClass;
    }

    public void setRunnableClass(Class<? extends Runnable> runnableClass) {
        this.runnableClass = runnableClass;
    }

    public String getCorn() {
        return corn;
    }

    public void setCorn(String corn) {
        this.corn = corn;
    }

    @Override
    public String toString() {
        return "ScheduledFutureHolder{" +
                "scheduledFuture=" + scheduledFuture +
                ", runnableClass=" + runnableClass +
                ", corn='" + corn + '\'' +
                '}';
    }
}

5、启动类(将EnableScheduling注解去掉,不去也行)

package com.syx;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@SpringBootApplication
//@EnableScheduling
public class MainApp {
    public static void main(String[] args) {
        SpringApplication.run(MainApp.class,args);
    }
}
在Spring Boot中,可以使用Quartz库来实现动态移除定时任务。Quartz是一个强大的调度框架,可以在后台添加、修改、移除定时任务。通过集成Quartz,可以实现在不重启应用的情况下动态移除定时任务。 可以参考中的Demo来实现动态移除定时任务的功能。在这个Demo中,后台可以添加、修改、移除定时任务,并且可以查看当前任务的状态。具体的实现可以参考Git项目地址中提供的代码。 使用Spring Boot和Quartz实现动态移除定时任务的步骤如下: 1. 首先,需要在Spring Boot项目中添加Quartz的依赖。 2. 创建一个定时任务管理类,用于管理所有的定时任务。这个类可以包含添加、修改、移除定时任务的方法。 3. 在定时任务管理类中,定义一个方法来移除定时任务。这个方法可以接受一个任务的唯一标识符作为参数,然后使用Quartz提供的API来移除该任务。 4. 在需要移除定时任务的地方,调用定时任务管理类中的移除定时任务的方法,传入要移除的任务的标识符即可。 通过以上步骤,就可以实现在Spring Boot中动态移除定时任务的功能了。这样可以在不重启应用的情况下,根据需要随时移除指定的定时任务。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [Springboot2-Quartz 后台可动态配置的定时任务](https://download.csdn.net/download/qq_32923745/10981179)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [Spring Boot实现动态增加、删除、修改停止定时任务](https://blog.csdn.net/qq_43813937/article/details/104183541)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [springboot不重启应用动态添加修改删除定时任务(以cron定时方式为例)](https://blog.csdn.net/qq_37549757/article/details/94393282)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]
评论 16
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值