spring boot使用TaskScheduler实现动态增删启停定时任务

news2025/1/16 1:34:35

TaskScheduler

概述

TaskScheduler是spring 3.0版本后,自带了一个定时任务工具,不用配置文件,可以动态改变执行状态。也可以使用cron表达式设置定时任务。

被执行的类要实现Runnable接口

TaskScheduler是一个接口,它定义了6个方法
在这里插入图片描述

接口的6种方法

public interface TaskScheduler { 

/** 
* 提交任务调度请求 
* @param task 待执行任务   
* @param trigger 使用Trigger指定任务调度规则 
* @return 
*/
ScheduledFuture schedule(Runnable task, Trigger trigger);

/** 
* 提交任务调度请求 
* 注意任务只执行一次,使用startTime指定其启动时间  
* @param task 待执行任务 
* @param startTime 任务启动时间 
* @return 
*/
ScheduledFuture schedule(Runnable task, Date startTime);


/** 
* 使用fixedRate的方式提交任务调度请求 
* 任务首次启动时间由传入参数指定 
* @param task 待执行的任务  
* @param startTime 任务启动时间 
* @param period 两次任务启动时间之间的间隔时间,默认单位是毫秒 
* @return 
*/
ScheduledFuture scheduleAtFixedRate(Runnable task, Date startTime, long period);

/** 
* 使用fixedRate的方式提交任务调度请求 
* 任务首次启动时间未设置,任务池将会尽可能早的启动任务 
* @param task 待执行任务 
* @param period 两次任务启动时间之间的间隔时间,默认单位是毫秒 
* @return 
*/
ScheduledFuture scheduleAtFixedRate(Runnable task, long period);

/** 
* 使用fixedDelay的方式提交任务调度请求 
* 任务首次启动时间由传入参数指定 
* @param task 待执行任务 
* @param startTime 任务启动时间 
* @param delay 上一次任务结束时间与下一次任务开始时间的间隔时间,单位默认是毫秒 
* @return 
*/
ScheduledFuture scheduleWithFixedDelay(Runnable task, Date startTime, long delay);

/** 
* 使用fixedDelay的方式提交任务调度请求 
* 任务首次启动时间未设置,任务池将会尽可能早的启动任务 
* @param task 待执行任务 
* @param delay 上一次任务结束时间与下一次任务开始时间的间隔时间,单位默认是毫秒 
* @return 
*/
ScheduledFuture scheduleWithFixedDelay(Runnable task, long delay);
}

0、ThreadPoolTaskScheduler

在 ThreadPoolTaskSchedulerConfig 中定义 ThreadPoolTaskScheduler bean

@Configuration
public class ThreadPoolTaskSchedulerConfig {

    @Bean
    public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
        ThreadPoolTaskScheduler threadPoolTaskScheduler
          = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(5);
        threadPoolTaskScheduler.setThreadNamePrefix(
          "ThreadPoolTaskScheduler");
        return threadPoolTaskScheduler;
    }
}

配置的 bean threadPoolTaskScheduler 可以根据配置的池大小 5 异步执行任务。
请注意,所有与 ThreadPoolTaskScheduler 相关的线程名称都将以ThreadPoolTaskScheduler 为前缀。
让我们实现一个简单的任务,然后我们可以安排:

class RunnableTask implements Runnable{
    private String message;
    
    public RunnableTask(String message){
        this.message = message;
    }
    
    @Override
    public void run() {
        System.out.println(new Date()+" Runnable Task with "+message
          +" on thread "+Thread.currentThread().getName());
    }
}

1、schedule(Runnable task, Trigger trigger)

指定一个触发器执行定时任务。可以使用CronTrigger来指定Cron表达式,执行定时任务

如下:使用CronTrigger 来根据 cron 表达式调度任务,可以使用提供的触发器按照某个指定的节奏或时间表运行任务,在这种情况下,RunnableTask 将在每分钟的第 10 秒执行。

taskScheduler.schedule(new RunnableTask("Cron Trigger"), cronTrigger);

2、schedule(Runnable task, Date startTime);

指定一个具体时间点执行定时任务,可以动态的指定时间,开启任务,只执行一次

如下:配置一个任务在 1000 毫秒的固定延迟后运行,RunnableTask 将始终在一次执行完成和下一次执行开始之间运行 1000 毫秒。

taskScheduler.schedule(
  new Runnabletask("Specific time, 3 Seconds from now"),
  new Date(System.currentTimeMillis + 3000)
);

3、scheduleAtFixedRate(Runnable task, long period);

立即执行,循环任务,指定一个执行周期(毫秒计时)
PS:不管上一个周期是否执行完,到时间下个周期就开始执行

如下:安排一个任务以固定的毫秒速率运行,下一个 RunnableTask 将始终在 2000 毫秒后运行,而不管上次执行的状态如何,它可能仍在运行。

taskScheduler.scheduleAtFixedRate(
  new RunnableTask("Fixed Rate of 2 seconds") , 
  2000);

4、scheduleAtFixedRate(Runnable task, Date startTime, long period);

指定时间开始执行,循环任务,指定一个间隔周期(毫秒计时)
PS:不管上一个周期是否执行完,到时间下个周期就开始执行

如下:使用CronTrigger 来根据 cron 表达式调度任务,可以使用提供的触发器按照某个指定的节奏或时间表运行任务,在这种情况下,RunnableTask 将在每分钟的第 10 秒执行。

taskScheduler.scheduleAtFixedRate(new RunnableTask(
  "Fixed Rate of 2 seconds"), new Date(), 3000);

5、scheduleWithFixedDelay(Runnable task, long delay);

立即执行,循环任务,指定一个间隔周期(毫秒计时)
PS:上一个周期执行完,等待delay时间,下个周期开始执行

如下:配置一个任务在 1000 毫秒的固定延迟后运行,RunnableTask 将始终在一次执行完成和下一次执行开始之间运行 1000 毫秒。

taskScheduler.scheduleWithFixedDelay(
  new RunnableTask("Fixed 1 second Delay"), 
  1000);

6、scheduleWithFixedDelay(Runnable task, Date startTime, long delay);

指定时间开始执行,循环任务,指定一个间隔周期(毫秒计时)
PS:上一个周期执行完,等待delay时间,下个周期开始执行

如下:将任务配置为在给定开始时间的固定延迟后运行,RunnableTask 将在指定的执行时间被调用,其中包括 @PostConstruct 方法开始的时间,随后延迟 1000 毫秒。

taskScheduler.scheduleWithFixedDelay(
  new RunnableTask("Current Date Fixed 1 second Delay"),
  new Date(),
  1000);

接口5个实现类

在这里插入图片描述

1、ConcurrentTaskScheduler

以当前线程执行任务,如果任务简单,可以直接使用这个类来执行,快捷方便

单线程运行

public class LocTest implements Runnable {
  private ConcurrentTaskScheduler concurrentTaskScheduler = new ConcurrentTaskScheduler();
  private void start() {
    concurrentTaskScheduler.schedule(this, new Date());
  }
  public void run() {
    Thread thread = Thread.currentThread();
    System.out.println("current id:" + thread.getId());
    System.out.println("current name:" + thread.getName());
  }
  public static void main(String[] args) {
    new LocTest().start();
  }
}

2、DefaultManagedTaskScheduler

以当前线程执行任务,是ConcurrentTaskScheduler的子类,添加了JNDI的支持。

和ConcurrentTaskScheduler一样的用法,需要使用JNDI可以单独设置

3、ThreadPoolTaskScheduler

TaskScheduler接口的默认实现类,多线程定时任务执行。可以设置执行线程池数(默认一个线程)

  1. 使用前必须得先调用initialize()【初始化方法】
  2. 有shutDown()方法,执行完后可以关闭线程

除实现了TaskScheduler接口中的方法外,它还包含了一些对ScheduledThreadPoolExecutor进行操作的接口,其常用方法如下:

  1. setPoolSize设置线程池大小,最小为1,默认情况下也为1
  2. setErrorHandler设置异常处理器
  3. getScheduledThreadPoolExecutor获取ScheduledExecutor,默认ScheduledThreadPoolExecutor类型
  4. getActiveCount获取当前活动的线程数
  5. execute提交执行一次的任务
  6. submit\submitListenable提交执行一次的任务,并且返回一个Future对象供判断任务状态使用
public class LocTest implements Runnable {
	private ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
	private void start() {
		taskScheduler.setPoolSize(10);
		//必须得先初始化,才能使用
		taskScheduler.initialize();
		taskScheduler.schedule(this, new Date());
	}
	public void run() {
		Thread ct = Thread.currentThread();
		System.out.println("current id:"+ct.getId());
		System.out.println("current name:"+ct.getName());
	}
	public static void main(String[] args) {
		new LocTest().start();
	}
}

4、TimerManagerTaskScheduler

用于包装CommonJ中的TimerManager接口。在使用CommonJ进行调度时使用

spring boot使用TaskScheduler实现动态增删启停定时任务

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

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;

@Configuration
public class SchedulingConfig {

    @Bean
    public TaskScheduler taskScheduler() {
        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 定时任务执行线程池核心线程数
        taskScheduler.setPoolSize(4);
        taskScheduler.setRemoveOnCancelPolicy(true);
        taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
        return taskScheduler;
    }
}

ScheduledTask:添加ScheduledFuture的包装类

ScheduledFuture是ScheduledExecutorService定时任务线程池的执行结果。

import java.util.concurrent.ScheduledFuture;


public final class ScheduledTask {
    volatile ScheduledFuture<?> future;

    /**
     * 取消定时任务
     */
    public void cancel() {
        ScheduledFuture<?> future = this.future;
        if (future != null) {
            future.cancel(true);
        }
    }
}

SchedulingRunnable:添加Runnable接口实现类

添加Runnable接口实现类,被定时任务线程池调用,用来执行指定bean里面的方法

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;
import java.util.Objects;


public class SchedulingRunnable implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);

    private final String beanName;

    private final String methodName;

    private final 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("定时任务开始执行 - bean:{},方法:{},参数:{}", 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("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", beanName, methodName, params), ex);
        }

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

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

import com.example.testspringboot.cron.ScheduleResult;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.config.CronTask;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 添加定时任务注册类,用来增加、删除定时任务。
 */
@Component
public class CronTaskRegistrar implements DisposableBean {

    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);
    private final Map<Integer, ScheduleResult> schedulerJob = new HashMap<>();
    @Autowired
    private TaskScheduler taskScheduler;

    public TaskScheduler getScheduler() {
        return this.taskScheduler;
    }

    public void addCronTask(ScheduleResult scheduleResult) {
        SchedulingRunnable task = new SchedulingRunnable(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
        String cronExpression = scheduleResult.getCronExpression();

        CronTask cronTask = new CronTask(task, cronExpression);
        // 如果当前包含这个任务,则移除
        if (this.scheduledTasks.containsKey(task)) {
            removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
        }
        schedulerJob.put(scheduleResult.getJobId(), scheduleResult);
        this.scheduledTasks.put(task, scheduleCronTask(cronTask));
    }

    public void removeCronTask(String beanName, String methodName, String methodParams) {
        SchedulingRunnable task = new SchedulingRunnable(beanName, methodName, methodParams);
        ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
        if (scheduledTask != null) {
            scheduledTask.cancel();
        }
    }

    public void removeCronTask(ScheduleResult scheduleResult) {
        schedulerJob.put(scheduleResult.getJobId(), scheduleResult);
        removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
    }

    public ScheduledTask scheduleCronTask(CronTask cronTask) {
        ScheduledTask scheduledTask = new ScheduledTask();
        scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
        return scheduledTask;
    }


    public Map<Runnable, ScheduledTask> getScheduledTasks() {
        return scheduledTasks;
    }

    public Map<Integer, ScheduleResult> getSchedulerJob() {
        return schedulerJob;
    }

    @Override
    public void destroy() {
        for (ScheduledTask task : this.scheduledTasks.values()) {
            task.cancel();
        }

        this.scheduledTasks.clear();
    }

    public ScheduleResult getSchedulerByJobId(Integer jobId) {
        for (ScheduleResult job : findAllTask()) {
            if (jobId.equals(job.getJobId())) {
                return job;
            }
        }
        return null;
    }

    public List<ScheduleResult> findAllTask() {
        List<ScheduleResult> ScheduleResults = new ArrayList<>();
        Set<Map.Entry<Integer, ScheduleResult>> entries = schedulerJob.entrySet();
        for (Map.Entry<Integer, ScheduleResult> en : entries) {
            ScheduleResults.add(en.getValue());
        }
        return ScheduleResults;
    }


}

CronUtils:校验Cron表达式的有效性

import org.springframework.scheduling.support.CronExpression;

public class CronUtils {
    /**
     * 返回一个布尔值代表一个给定的Cron表达式的有效性
     *
     * @param cronExpression Cron表达式
     * @return boolean 表达式是否有效
     */
    public static boolean isValid(String cronExpression) {
        return CronExpression.isValidExpression(cronExpression);
    }


}

ScheduleResult:添加定时任务实体类

import lombok.Data;


@Data
public class ScheduleResult {
    /**
     * 任务ID
     */
    private Integer jobId;
    /**
     * bean名称
     */
    private String beanName;
    /**
     * 方法名称
     */
    private String methodName;
    /**
     * 方法参数: 执行service里面的哪一种方法
     */
    private String methodParams;
    /**
     * cron表达式
     */
    private String cronExpression;
    /**
     * 状态(1正常 0暂停)
     */
    private Integer jobStatus;
    /**
     * 备注
     */
    private String remark;
    /**
     * 创建时间
     */
    private String createTime;
    /**
     * 更新时间
     */
    private String updateTime;

}

ScheduleJobStatus:任务状态枚举类型

public enum ScheduleJobStatus {
    /**
     * 暂停
     */
    PAUSE,

    /**
     * 正常
     */
    NORMAL;


}

SpringContextUtils类:从spring容器里获取bean

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class SpringContextUtils implements ApplicationContextAware {

    private static ApplicationContext applicationContext = null;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        if (SpringContextUtils.applicationContext == null) {
            SpringContextUtils.applicationContext = applicationContext;
        }
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    // 通过name获取 Bean.
    public static Object getBean(String name) {
        return getApplicationContext().getBean(name);

    }

    // 通过class获取Bean.
    public static <T> T getBean(Class<T> clazz) {
        return getApplicationContext().getBean(clazz);

    }

    // 通过name,以及Clazz返回指定的Bean
    public static <T> T getBean(String name, Class<T> clazz) {
        return getApplicationContext().getBean(name, clazz);
    }

    public static boolean containsBean(String name) {
        return getApplicationContext().containsBean(name);
    }

    public static boolean isSingleton(String name) {
        return getApplicationContext().isSingleton(name);
    }

    public static Class<? extends Object> getType(String name) {
        return getApplicationContext().getType(name);
    }
}

ScheduleJobService:增删启停service方法

@Service
@Slf4j
public class ScheduleJobService {


    @Autowired
    private CronTaskRegistrar cronTaskRegistrar;

    public void addScheduleJob(ScheduleResult scheduleResult) {
        long currentTimeMillis = System.currentTimeMillis();
        scheduleResult.setCreateTime(formatTimeYMD_HMS_SSS(currentTimeMillis));
        scheduleResult.setUpdateTime(formatTimeYMD_HMS_SSS(currentTimeMillis));
        scheduleResult.setJobId(findAllTask().size() + 1);
        if (scheduleResult.getJobStatus().equals(ScheduleJobStatus.NORMAL.ordinal())) {
            log.info("Stop or pause: is now on");
            cronTaskRegistrar.addCronTask(scheduleResult);
            return;
        }
        cronTaskRegistrar.getSchedulerJob().put(scheduleResult.getJobId(), scheduleResult);
    }

    public void editScheduleJob(ScheduleResult currentSchedule) {
        //先移除
        cronTaskRegistrar.removeCronTask(currentSchedule.getBeanName(), currentSchedule.getMethodName(), currentSchedule.getMethodParams());
        ScheduleResult pastScheduleJob = cronTaskRegistrar.getSchedulerByJobId(currentSchedule.getJobId());
        if (pastScheduleJob == null) {
            System.out.println("没有这个任务");
            return;
        }
        //然后判断是否开启, 如果开启的话,现在立即执行
        startOrStopSchedulerJob(currentSchedule, true);
    }

    public void deleteScheduleJob(ScheduleResult scheduleResult) {
        // 清除这个任务
        cronTaskRegistrar.removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
        // 清除这个任务的数据
        cronTaskRegistrar.getSchedulerJob().remove(scheduleResult.getJobId());
    }

    public void startOrStopScheduler(ScheduleResult scheduleResult) {
        cronTaskRegistrar.getSchedulerJob().get(scheduleResult.getJobId()).setJobStatus(scheduleResult.getJobStatus());
        startOrStopSchedulerJob(scheduleResult, false);
    }

    private void startOrStopSchedulerJob(ScheduleResult scheduleResult, boolean update) {
        // 更新时间
        scheduleResult.setUpdateTime(formatTimeYMD_HMS_SSS(System.currentTimeMillis()));
        if (scheduleResult.getJobStatus().equals(ScheduleJobStatus.NORMAL.ordinal())) {
            System.out.println("停止或暂停:现在是开启");
            cronTaskRegistrar.addCronTask(scheduleResult);
            return;
        }
        System.out.println("停止或暂停:现在是暂停");
        if (update){
            cronTaskRegistrar.removeCronTask(scheduleResult);
            return;
        }
        cronTaskRegistrar.removeCronTask(scheduleResult.getBeanName(), scheduleResult.getMethodName(), scheduleResult.getMethodParams());
    }

    public List<ScheduleResult> findAllTask() {
        return cronTaskRegistrar.findAllTask();
    }


    // 转换为年-月-日 时:分:秒
    private String formatTimeYMD_HMS_SSS(long time) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS").format(time);
    }

}

cronController:访问接口

import com.example.testspringboot.cron.ScheduleResult;
import com.example.testspringboot.cron.ScheduleJobService;
import com.example.testspringboot.cron.utils.CronUtils;
import com.google.gson.Gson;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
public class cronController {
    @Autowired
    private ScheduleJobService scheduleJobService;
    /**
     * 测试上传的用例文件, 获取详细执行结果
     */
    @PostMapping("/add")
    void executeTestOneFile(@RequestBody ScheduleResult scheduleResult) {
        boolean valid = CronUtils.isValid(scheduleResult.getCronExpression());
        if (valid){
            System.out.println("校验成功, 添加任务");
            scheduleResult.setMethodParams(scheduleResult.getBranch()+scheduleResult.getCaseDir());
            scheduleJobService.addScheduleJob(scheduleResult);
        }else {
            System.out.println("校验失败");
        }
    }

    @PostMapping("/stop")
    void end(@RequestBody ScheduleResult scheduleResult) {
        Gson gson = new Gson();

        System.out.println("================");
        System.out.println(scheduleResult);
        System.out.println("=================");
        scheduleResult.setJobStatus(0);
        scheduleJobService.startOrStopScheduler(scheduleResult);
    }
    @PostMapping("/start")
    void start(@RequestBody ScheduleResult scheduleResult) {
        System.out.println("================");
        System.out.println(scheduleResult);
        System.out.println("=================");
        scheduleResult.setJobStatus(1);
        scheduleJobService.startOrStopScheduler(scheduleResult);
    }

    @PostMapping("/edit")
    void edit(@RequestBody ScheduleResult scheduleResult) {
        System.out.println("=======edit=========");
        System.out.println(scheduleResult);
        System.out.println("=================");
        scheduleJobService.editScheduleJob(scheduleResult);
    }

    @PostMapping("/delete")
    void delete(@RequestBody ScheduleResult scheduleResult) {
        System.out.println("=======delete=========");
        System.out.println(scheduleResult);
        System.out.println("=================");
        scheduleJobService.deleteScheduleJob(scheduleResult);
    }

    @GetMapping("/tasks")
    List<ScheduleResult> get() throws Exception {
        List<ScheduleResult> allTask = scheduleJobService.findAllTask();
        System.out.println("现在的定时任务数量 = " + allTask.size());
        System.out.println("现在的定时任务 = " + allTask);
        return allTask;
    }


}

c1:测试bean

import org.springframework.stereotype.Component;

@Component
public class c1 {
    public void test1(String y){
        System.out.println("这个是test1的bean : " + y);
    }
    public void test2(){
        System.out.println("这个是test1的bean中test2方法");
    }
}

init:项目启动后的定时任务

import com.example.testspringboot.cron.ScheduleJobService;
import com.example.testspringboot.cron.ScheduleResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class init  implements CommandLineRunner {
    @Autowired
    private ScheduleJobService scheduleJobService;

    @Override
    public void run(String... args) throws Exception {
        System.out.println("开始珍惜");
        ScheduleResult scheduleResult = new ScheduleResult();
        scheduleResult.setBeanName("c1");
        scheduleResult.setMethodName("test1");
        scheduleResult.setCronExpression("0/25 * * * * *");
        scheduleResult.setJobStatus(1);
        scheduleResult.setMethodParams("test1");
        scheduleJobService.addScheduleJob(scheduleResult);
        scheduleJobService.findAllTask();
    }
}

后续的操作,基本上就是复制粘贴,运行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/145279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

具有梯度流的一类系统的扩散图卡尔曼滤波(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

FEW-SHOT TEXT CLASSIFICATION WITH DISTRIBUTIONAL SIGNATURES

摘要 在这篇文章中&#xff0c;我们利用元学习进行文本分类&#xff0c;元学习在计算机视觉中有相当好的效果&#xff0c;在这里&#xff0c;低层次的模式可以跨学习任务迁移的&#xff0c;&#xff0c;然而&#xff0c;直接将这个方法应用到文本中是具有挑战性的&#xff0c;…

【自学C++】C++输入cin

C输入cin C输入cin教程 在 C 语言 中我们需要捕获用户的键盘输入&#xff0c;可以使用 scanf 函数。scanf 函数在输入时&#xff0c;我们必须要指定输入的数据类型对应的格式化符&#xff0c;挺不方便。 在 C 中&#xff0c;我们要捕捉用户的输入&#xff0c;直接使用 std 命…

【目标检测】C-GhostNet

1、论文 论文题名:《GhostNet: More Features from Cheap Operations》 arxiv&#xff1a;https://arxiv.org/abs/1911.11907 github&#xff1a;https://github.com/huawei-noah/ghostnet 作者翻译&#xff1a;https://zhuanlan.zhihu.com/p/109325275 2、摘要 本篇论文是华…

2023/1/6 Vue学习笔记-2

1 收集表单数据 收集表单数据&#xff1a; 若&#xff1a;<input type"text">&#xff0c;则v-model收集的是value的值&#xff0c;用户输入的就是value值。 若&#xff1a;<input type"radio">&#xff0c;则v-modle收集的是value的值&…

String、StringBuffer和StringBuilder

String 类是不可变类&#xff0c;即一旦一个 String 对象被创建以后&#xff0c;包含在这个对象中的字符序列是不可改变的&#xff0c;直至这个对象被销毁。 Java 提供了两个可变字符串类 StringBuffer 和 StringBuilder&#xff0c;中文翻译为“字符串缓冲区”。 StringBuil…

Python和MySQL对比(3):用Pandas 实现MySQL的子查询、like_regexp、case when_if语法效果

文章目录一、前言二、语法对比数据表子查询like/regexpcase when/ifin三、小结一、前言 环境&#xff1a; windows11 64位 Python3.9 MySQL8 pandas1.4.2 本文主要介绍 MySQL 中的子查询、like/regexp、case when/if 如何使用pandas实现&#xff0c;同时二者又有什么区别。 注…

FPGA中二进制数的运算

一、B比特的二进制数可以表示的范围 无符号整数&#xff1a;0~2B-1 有符号整数&#xff1a;-2B-1~2B-1-1 二、有符号数&#xff08;补码&#xff09;与十进制数之间的转换 D&#xff1a;十进制数 B&#xff1a;二进制数aB-1aB-2a1a0的位数 aB-1:符号位 三、符号位拓展 在使…

Android 12 蓝牙适配 Java版

Android 12.0蓝牙适配前言正文一、Android版本中蓝牙简介二、新建项目① 配置build.gradle② 配置AndroidManifest.xml三、打开蓝牙① 打开蓝牙意图② 请求BLUETOOTH_CONNECT权限意图四、蓝牙扫描① 扫描者② 扫描回调③ 扫描方法④ 执行扫描⑤ 应用不推导物理位置五、页面显示…

基于Java+Springboot+vue体育用品销售商城平台设计和实现

基于JavaSpringbootvue体育用品销售商城平台设计和实现 博主介绍&#xff1a;5年java开发经验&#xff0c;专注Java开发、定制、远程、文档编写指导等,csdn特邀作者、专注于Java技术领域 作者主页 超级帅帅吴 Java毕设项目精品实战案例《500套》 欢迎点赞 收藏 ⭐留言 文末获取…

Docker部署JAVA项目

一、 Docker安装 1、yum 包更新到最新 yum update 2、安装需要的软件包&#xff0c; yum-util 提供yum-config-manager功能&#xff0c;另外两个是devicemapper驱动依赖的 yum install yum-utils device-mapper-persistent-data lvm2 -y 3、 设置yum源 yum-config-manage…

等级保护----1、网络安全等级保护一级安全测评要求

文章目录一、安全测评通用要求1、安全物理环境1.1 物理访问控制1.2 防盗窃和防破坏1.3 防雷击1.4 防火1.5 防水和防潮1.6 温湿度控制1.7 电力供应2、安全通信网络2.1 通信传输2.2 可信验证3、安全区域边界3.1 边界防护3.2 访问控制3.3 可信验证4、安全计算环境4.1 身份鉴别4.2 …

使用关键字like进行模糊查询

【模糊查询】&#xff1a;使用关键字like [支持%或者下划线匹配&#xff0c;%匹配任意多个字符&#xff0c;一个下划线只匹配任意一个字符。] 实例&#xff1a; 查询名字中带有字母o的员工&#xff1a; select * from emp where ename like %o%; 找出名字以T结…

2000-2021.3月土地交易高频数据库(含爬取代码和数据)

2000-2021.3月土地交易高频数据库&#xff08;含爬取代码和数据&#xff09; 1、时间跨度&#xff1a;2000-2021年3月1日 2、指标&#xff1a;年份、电子监管号、所在省份、所在城市、所在区县、经度、纬度、项目名称、项目位置、面积、土地来源、土地用途、供地方式、土地使…

Python CV 实现风格化图片转换

前几天遇到一个风格化图片转换的需求&#xff0c;效果像这样&#xff1a; 像这样&#xff0c;需要用纯色圆形填充图像&#xff0c;形成风格化的图片样式。 实现原理 整体原理还是比较简单的&#xff0c;有点类似与马赛克的处理方式。 假设图片宽 w 像素&#xff0c;高 h 像素…

FLStudio21中文版下载及水果软件2023功能介绍

如今&#xff0c;越来越多的音乐人选择使用音乐制作软件来进行音乐的创作&#xff0c;一台电脑、一款软件以及一个外接MIDI就是一个小型的音乐工作站&#xff0c;而如今非常流行的FL Studio&#xff08;在国内被称为“水果”&#xff09;成了音乐界无论萌新还是大佬们的首选&am…

二阶微分算子与反锐化屏蔽

二阶微分算子 任意二阶微分必须满足&#xff1a;灰度不变的区域微分值为0&#xff1b;灰度台阶或斜坡的起点处微分值非0&#xff1b;沿着斜坡的微分值为0。由于处理离散值&#xff0c;因此微分用差分近似&#xff1a; 二维图像f(x,y),沿着两个空间坐标轴求解二阶微分&#xff1…

逆向-还原代码之little-or-big (Arm 64)

// 源代码 #include <stdio.h> /* * 2016/9/29 yu liang. */ int test_one(void) { int i1; char *p(char *)&i; if(*p1) printf("Little_endian\n"); // Little_endian else printf("B…

一文弄清楚Vue中的computed与watch的区别

1.实现业务当我们点击按钮&#xff0c;就会切换h1标签的语句内容&#xff0c;再次点击按钮&#xff0c;h1标签的语句内容就会恢复&#xff0c;每次点击按钮&#xff0c;浏览器都会输出一个语句来表达监视到了h1的内容改变2.Vue中的computed计算属性2.1利用Vue中的computed计算属…

Windows server——部署DHCP服务

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 本章重点 一.DHCP概述 1.DHCP服务的好处 二.DHCP的工作原理 1.DHCP的分配方…