springboot创建动态定时任务的几种方式小结-kb88凯时官网登录

时间:2024-10-20
阅读:
免费资源网,https://freexyz.cn/

一、使用 @scheduled 注解

@scheduled 是 spring 提供的一个注解,用于标记需要定时执行的方法。常见的属性包括:

  • cron :通过 cron 表达式定义任务的执行时间。
  • fixedrate :定义任务的固定执行频率,以毫秒为单位。
  • fixeddelay :定义任务在前一次执行完毕后延迟多少毫秒再执行。

代码示例:

import org.springframework.scheduling.annotation.scheduled;
import org.springframework.stereotype.component;
 
@component
public class scheduledtasks {
 
    @scheduled(cron = "0 0 * * * ?") // 每小时整点执行一次
    public void reportcurrenttime() {
        system.out.println("现在时间:"   system.currenttimemillis());
    }
 
    @scheduled(fixedrate = 5000) // 每5秒执行一次
    public void fixedratetask() {
        system.out.println("每5秒执行一次任务:"   system.currenttimemillis());
    }
 
    @scheduled(fixeddelay = 7000) // 前一次执行完毕后延迟7秒执行
    public void fixeddelaytask() {
        system.out.println("延迟7秒后执行任务:"   system.currenttimemillis());
    }
}

@scheduled 适用于大多数简单的定时任务场景,如定时发送邮件或生成报告等。然而,它的灵活性较差,对于复杂的任务调度需求,或需要动态调整任务时间的场景,可能并不适用。

二、使用 schedulingconfigurer 接口

schedulingconfigurer 接口允许我们通过编程方式配置任务调度器(taskscheduler)。通过实现这个接口,我们可以灵活地设置任务的调度规则,甚至动态地添加或移除任务。

简单使用代码:

public class taskconfig implements schedulingconfigurer {
    
    @override
    public void configuretasks(scheduledtaskregistrar scheduledtaskregistrar) {
        scheduledtaskregistrar.addtriggertask(
                //1.添加任务内容(runnable)
                () -> system.out.println("执行定时任务2: "   localdatetime.now().tolocaltime()),
                //2.设置执行周期(trigger)
                triggercontext -> {
                    //2.1 从数据库获取执行周期
                    string cron = zhymapper.getcron();
                    //2.2 合法性校验.
                    if (stringutils.isempty(cron)) {
                        // omitted code ..
                    }
                    //2.3 返回执行周期(date)
                    return new crontrigger(cron).nextexecutiontime(triggercontext);
                }
        );
 
    }
}

详细增删该查操作:

  • 动态注册bean
public class applicationcontextutils implements applicationcontextaware {
 
    private static applicationcontext context;
    /**
     * 设置spring上下文
     * @param ctx spring上下文
     * @throws beansexception
     * */
    @override
    public void setapplicationcontext(applicationcontext ctx) throws beansexception {
        context = ctx;
    }
 
    /**
     * 获取容器
     * @return
     */
    public static applicationcontext getapplicationcontext() {
        return context;
    }
 
    /**
     * 获取容器对象
     * @param type
     * @param 
     * @return
     */
    public static  t getbean(class type) {
        return context.getbean(type);
    }
 
    public static  t getbean(string name,class clazz){
        return context.getbean(name, clazz);
    }
 
    public static object getbean(string name){
        return context.getbean(name);
    }
 
    /**
     * springboot动态注册bean
     * @param clazz
     * @param 
     * @return
     */
    public static  t register(class clazz) {
		configurableapplicationcontext configurableapplicationcontext = (configurableapplicationcontext) applicationcontextutils.getapplicationcontext();
		defaultlistablebeanfactory defaultlistablebeanfactory = (defaultlistablebeanfactory) configurableapplicationcontext.getbeanfactory();
		beandefinitionbuilder beandefinitionbuilder = beandefinitionbuilder.genericbeandefinition(clazz);
        if(defaultlistablebeanfactory.getbeannamesfortype(clazz).length > 0) {
            return defaultlistablebeanfactory.getbean(clazz);
        }
		defaultlistablebeanfactory.registerbeandefinition(clazz.getname(), beandefinitionbuilder.getrawbeandefinition());
		return (t) applicationcontextutils.getbean(clazz.getname());
    }
}
 
  • 任务实体
public class job {
 
    /**
     * 任务id, 用于标识,默认使用全限定类名
     */
    private string jobid;
 
    /**
     * 任务名称, 默认简单类名
     */
    private string jobname;
 
    /**
     * cron表达式, 修改后即可生效
     */
    private string cron;
 
    /**
     * 任务描述
     */
    private string description;
 
    /**
     * 是否启用, 默认启用, 修改后即可生效
     */
    private boolean enable = true;
 
    /**
     * 是否处于等待执行下个任务的状态
     */
    private boolean active;
    /**
     * 任务运行类
     */
    private class clazz;
}
  • 操作类
public class jobhandler {
 
    private scheduledtask scheduledtask;
 
    private triggertask triggertask;
 
    private triggercontext triggercontext;
}
  • 配置schedulingconfigurer
public class jobschedulingconfigurer implements schedulingconfigurer {
 
    private scheduledtaskregistrar registrar;
 
    /**
     * 线程池任务调度器
     */
    @bean
    public taskscheduler taskscheduler() {
        threadpooltaskscheduler scheduler = new threadpooltaskscheduler();
        scheduler.setpoolsize(runtime.getruntime().availableprocessors() / 3   1);
        scheduler.setthreadnameprefix("taskscheduler-");
        scheduler.setremoveoncancelpolicy(true);  // 保证能立刻丢弃运行中的任务
 
        taskscheduler = scheduler; // 获取 句柄,方便后期获取 future
 
        return scheduler;
    }
 
    @override
    public void configuretasks(scheduledtaskregistrar scheduledtaskregistrar) {
        scheduledtaskregistrar.settaskscheduler(taskscheduler());
        this.registrar = scheduledtaskregistrar;
    }
 
    public scheduledtaskregistrar getregistrar() {
        return registrar;
    }
 
    public void setregistrar(scheduledtaskregistrar registrar) {
        this.registrar = registrar;
    }
}
  • 增删改查
public class schedulermanager {
 
    /**
     * 任务容器
     */
    private map tasks = new concurrenthashmap<>();
 
    /**
     * 任务注册
     */
    @autowired
    private jobschedulingconfigurer register;
 
    /**
     * 新增任务, 自生效
     * @param job 任务实体
     * @return 返回新增的任务
     */
    public job addjob(job job) {
        assert.notnull(job, "job can't be null");
        scheduledtaskregistrar registrar = register.getregistrar();
        runnable runnable = applicationcontextutils.register(job.getclazz());
        if(job.getjobid() == null || "".equals(job.getjobid())) {
            job.setjobid(job.getclazz().getname());
        }
        assert.isnull(this.getjob(job.getjobid()), "任务["   job.getjobid()   "]已存在");
        if(job.getjobname() == null || "".equals(job.getjobname())) {
            job.setjobname(classutils.getshortname(job.getclazz()));
        }
        cronexpress cron = annotationutils.findannotation(job.getclazz(), cronexpress.class);
        if(cron != null && !"".equals(cron.value())) {
            // 注解的属性,大于配置的属性,方便调试
            job.setcron(cron.value());
        }
        job.setenable(true);
        job.setactive(true);
        jobhandler entity = new jobhandler();
        triggertask triggertask = new triggertask(runnable, (triggercontext triggercontext) -> {
            // 每次任务执行均会进入此方法
            crontrigger trigger = new crontrigger(job.getcron());
            entity.settriggercontext(triggercontext);
            return job.isenable() ? trigger.nextexecutiontime(triggercontext) : null;
        });
        scheduledtask scheduledtask = registrar.scheduletriggertask(triggertask);
        entity.setscheduledtask(scheduledtask);
        entity.settriggertask(triggertask);
        tasks.put(job, entity);
        return job;
    }
 
    /**
     * 任务类(必须标注了@cronexpress注解,且实现了runnable接口)
     * @param clazz 接口类
     * @return 任务对象
     */
    public job addjob(class clazz) {
        job job = new job();
        job.setclazz(clazz);
        return this.addjob(job);
    }
 
    /**
     * 获取任务操作对象
     * @param jobid 任务id
     * @return 任务操作对象
     */
    public jobhandler getjobhandler(string jobid) {
        return tasks.get(new job(jobid));
    }
 
    /**
     * 根据任务id获取任务
     * @param jobid 任务id
     * @return 任务实体
     */
    public job getjob(string jobid) {
        assert.hastext(jobid, "jobid can't be null");
        set jobs = tasks.keyset();
        if(jobs.size() == 0) {
            return null;
        }
        iterator iterator = jobs.iterator();
        while (iterator.hasnext()) {
            job next = iterator.next();
            if(jobid.equals(next.getjobid())) {
                return next;
            }
        }
        return null;
    }
 
    /**
     * 关闭任务(若任务正在执行,待任务执行完)
     * @param jobid 任务id
     * @return 是否关闭成功
     */
    public boolean shutdown(string jobid) {
        try {
            jobhandler handler = this.getjobhandler(jobid);
            assert.notnull(handler, "任务["   jobid   "]不存在");
            handler.getscheduledtask().cancel();
            job job = getjob(jobid);
            job.setactive(false);
            return true;
        } catch (exception e) {
            return false;
        }
    }
 
    /**
     * 启动已经注册的任务
     * @param jobid 任务id
     * @return 是否成功启动
     */
    public boolean startup(string jobid) {
        try {
            jobhandler handler = this.getjobhandler(jobid);
            assert.notnull(handler, "任务["   jobid   "]不存在");
            register.getregistrar().scheduletriggertask(handler.gettriggertask());
            job job = getjob(jobid);
            job.setactive(true);
            return true;
        } catch (exception e) {
            return false;
        }
    }
 
    /**
     * 获取所有的任务实体
     * @return
     */
    public list getjobs() {
        return new arraylist<>(tasks.keyset());
    }
 
    /**
     * 删除任务,先关闭再删除
     * @param jobid
     * @return
     */
    public boolean deletejob(string jobid) {
        try {
            job job = this.getjob(jobid);
            assert.notnull(job, "任务["   jobid   "]不存在");
            shutdown(jobid);
            tasks.remove(job);
            return true;
        } catch (exception e) {
            return false;
        }
    }
}
 
  • 任务运行类
@cronexpress("0/1 * * * * *")
public class hellojob implements runnable {
 
    @override
    public void run() {
        system.out.println("hello msg"   thread.currentthread().getid());
    }
}
  • 测试
configurableapplicationcontext ctx = springapplication.run(unifiedtaskschedulestarterapplication.class, args);
schedulermanager schedulermanager = ctx.getbean(schedulermanager.class);
job job = schedulermanager.addjob(com.github.softwarevax.web.hellojob.class);
schedulermanager.shutdown(job.getjobid());

三、使用 taskscheduler

taskscheduler 是spring提供的用于调度任务的核心接口。通过 taskscheduler,你可以灵活地安排任务的执行时间,并且可以在运行时动态地创建、取消任务。

代码示例简单使用:

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 taskschedulerconfig {
 
    @bean
    public taskscheduler taskscheduler() {
        threadpooltaskscheduler scheduler = new threadpooltaskscheduler();
        scheduler.setpoolsize(5);
        scheduler.setthreadnameprefix("myscheduler-");
        return scheduler;
    }
}

在使用 taskscheduler 时,可以通过 schedule 方法动态安排任务:

import org.springframework.beans.factory.annotation.autowired;
import org.springframework.scheduling.taskscheduler;
import org.springframework.stereotype.component;
 
import java.util.date;
 
@component
public class dynamictask {
 
    @autowired
    private taskscheduler taskscheduler;
 
    public void scheduletask() {
        taskscheduler.schedule(() -> system.out.println("动态任务执行:"   system.currenttimemillis()), new date(system.currenttimemillis()   5000));
    }
}

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 scheduledtasks = new concurrenthashmap<>(16);
    private final map 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 getscheduledtasks() {
        return scheduledtasks;
    }
 
    public map 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 findalltask() {
        list scheduleresults = new arraylist<>();
        set> entries = schedulerjob.entryset();
        for (map.entry 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 getbean(class clazz) {
        return getapplicationcontext().getbean(clazz);
    }
 
    // 通过name,以及clazz返回指定的bean
    public static  t getbean(string name, class 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 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 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 get() throws exception {
        list alltask = schedulejobservice.findalltask();
        system.out.println("现在的定时任务数量 = "   alltask.size());
        system.out.println("现在的定时任务 = "   alltask);
        return alltask;
    }
}
  • 测试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方法");
    }
}
  • 项目启动后的定时任务
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();
    }
}

四、使用 quartz 实现定时任务

quartz 是一个功能强大的开源任务调度框架,支持复杂的任务调度需求,如任务的持久化、分布式任务管理、基于数据库的调度等。spring boot 提供了对 quartz 的良好集成,使得在应用中使用 quartz 变得更加简单。

简单使用:

import org.quartz.*;
import org.springframework.context.annotation.bean;
import org.springframework.context.annotation.configuration;
import org.springframework.scheduling.quartz.jobdetailfactorybean;
import org.springframework.scheduling.quartz.simpletriggerfactorybean;
 
@configuration
public class quartzconfig {
 
    @bean
    public jobdetailfactorybean jobdetail() {
        jobdetailfactorybean factorybean = new jobdetailfactorybean();
        factorybean.setjobclass(samplejob.class);
        factorybean.setdescription("sample quartz job");
        factorybean.setdurability(true);
        return factorybean;
    }
 
    @bean
    public simpletriggerfactorybean trigger(jobdetail jobdetail) {
        simpletriggerfactorybean factorybean = new simpletriggerfactorybean();
        factorybean.setjobdetail(jobdetail);
        factorybean.setrepeatinterval(5000); // 每5秒执行一次
        factorybean.setrepeatcount(simpletrigger.repeat_indefinitely);
        return factorybean;
    }
 
    public static class samplejob implements job {
        @override
        public void execute(jobexecutioncontext context) {
            system.out.println("quartz任务执行:"   system.currenttimemillis());
        }
    }
}

springboot整合

  • 数据库设计

将任务计划放入数据库中保存。在启动任务是,从数据库中查找任务计划信息,并动态配置进去即可。

drop table if exists `cc_task_info`;
 
create table `cc_task_info` (
  `tid` int(11) not null auto_increment,
  `task_anme` varchar(50) not null,
  `task_code` varchar(50) not null,
  `job_class` varchar(200) not null,
  `job_group` varchar(50) not null,
  `cron` varchar(50) not null,
  `del_status` varchar(2) default '1' null,
  `crt_time` datetime default null,
  primary key (`tid`)
) engine=innodb auto_increment=1 default charset=utf8 comment='定时任务管理表';
 
drop table if exists `cc_task_record`;
 
create table `cc_task_record` (
  `rid` int(11) not null auto_increment,
  `task_code` varchar(50) not null,
  `run_time` datetime not null,
  `run_code` char(1) not null,
  `run_msg` varchar(100) null,
  primary key (`rid`)
) engine=innodb auto_increment=1 default charset=utf8 comment='定时任务运行记录表';
 
drop table if exists `cc_task_status`;
 
create table `cc_task_status` (
  `task_code` varchar(50) not null,
  `task_status` varchar(10) not null,
  `lst_succ_time` datetime not null,
  `lst_time` datetime not null,
  primary key (`task_code`)
) engine=innodb auto_increment=1 default charset=utf8 comment='定时任务运行状态表';
  • 定时任务管理

通过scheduler的方法来实现。scheduler提供了一系列方法来管理定时任务的执行状态。

主要包括:

  • schedulejob():添加定时任务
  • reschedulejob():修改定时任务
  • pausejob():暂停定时任务执行
  • resumejob():恢复定时任务执行
  • deletejob():删除定时任务执行

针对上述方法,只需要传入对应参数即可。建了一个quartzservice来管理定时任务,供业务层调用。

详细代码如下:

/**
 * 定时任务管理服务
 */
@service
public class quartzservice {
 
    public static string scheduler_opr_start = "start";
    public static string scheduler_opr_pause = "pause";
    public static string scheduler_opr_resume = "resume";
    public static string scheduler_opr_remove = "remove";
 
    @autowired
    private scheduler scheduler;
 
    /**
     * 启动任务
     */
    public void startjob(string taskcode, string taskanme, string cron, string jobgroup,
                         string classname) throws exception{
        class jobclass = null;
        try {
            jobclass = (class) class.forname(classname);//获取任务执行类
        } catch (classnotfoundexception e) {
            throw new exception("任务类不存在");
        }
        //创建job,指定job名称和分组
        jobdetail jobdetail = jobbuilder.newjob(jobclass).withidentity(taskcode, jobgroup).build();
        //创建表达式工作计划
        cronschedulebuilder cronschedulebuilder = cronschedulebuilder.cronschedule(cron);
        //创建触发器
        crontrigger crontrigger = triggerbuilder.newtrigger().withidentity(taskcode, jobgroup)
                .withschedule(cronschedulebuilder).build();
        scheduler.schedulejob(jobdetail, crontrigger);
    }
 
    /**
     * 修改定时任务执行时间
     * @param taskcode
     * @param jobgroup
     * @param cron 新的时间
     * @throws exception
     */
    public void modifyjob(string taskcode, string jobgroup, string cron) throws exception{
        triggerkey triggerkey = new triggerkey(taskcode, jobgroup);
        crontrigger trigger = (crontrigger) scheduler.gettrigger(triggerkey);
        string oldcron = trigger.getcronexpression();
        if(!oldcron.equals(cron)){
            crontrigger crontrigger = triggerbuilder.newtrigger().withidentity(taskcode, jobgroup)
                    .withschedule(cronschedulebuilder.cronschedule(cron)).build();
            date date = scheduler.reschedulejob(triggerkey, crontrigger);
            if(date == null){
                throw new exception("修改定时任务执行时间报错");
            }
        }
    }
 
    /**
     * 暂停某个定时任务(任务恢复后,暂停时间段内未执行的任务会继续执行,如暂停时间段内有2次,则会执行2次)
     * @param taskcode
     * @param jobgroup
     * @throws exception
     */
    public void pausejob(string taskcode, string jobgroup) throws exception{
        jobkey jobkey = new jobkey(taskcode, jobgroup);
        jobdetail jobdetail = scheduler.getjobdetail(jobkey);
        if(jobdetail == null){
            return;
        }
        scheduler.pausejob(jobkey);
    }
 
    /**
     * 恢复某个定时任务
     * @param taskcode
     * @param jobgroup
     * @throws exception
     */
    public void resumejob(string taskcode, string jobgroup) throws exception{
        jobkey jobkey = new jobkey(taskcode, jobgroup);
        jobdetail jobdetail = scheduler.getjobdetail(jobkey);
        if(jobdetail == null){
            return;
        }
        scheduler.resumejob(jobkey);
    }
 
    /**
     * 删除某个定时任务
     * @param taskcode
     * @param jobgroup
     * @throws exception
     */
    public void deletejob(string taskcode, string jobgroup) throws exception{
        jobkey jobkey = new jobkey(taskcode, jobgroup);
        jobdetail jobdetail = scheduler.getjobdetail(jobkey);
        if(jobdetail == null){
            return;
        }
        scheduler.deletejob(jobkey);
    }
}
  • 编写任务类job

任务类job就是定时任务具体要处理的系统业务逻辑,需要实现job接口。

在任务启动时,通过jobclass传入jobdetail。

public class demojob implements job {
 
    @override
    public void execute(jobexecutioncontext jobexecutioncontext) throws jobexecutionexception {
        string taskcode = jobexecutioncontext.getjobdetail().getkey().getname();
        system.out.println("执行定时任务:"   taskcode);
    }
}
  • 配置scheduler

在configuration中配置scheduler实例,并启动。

@configuration
public class quartzconfig {
 
    @bean
    public scheduler scheduler(){
        scheduler scheduler = null;
        schedulerfactory factory = new stdschedulerfactory();
        try {
            scheduler = factory.getscheduler();
        } catch (schedulerexception e) {
            e.printstacktrace();
        }
        if(scheduler != null){
            try {
                //启动定时任务
                scheduler.start();
            } catch (schedulerexception e) {
                e.printstacktrace();
            }
        }
        return scheduler;
    }
}
  • 编写api接口

通过controller提供api接口,这里的taskservice调用了qartzservice的对应接口,并做了一个写数据库读写操作,主要记录定时任务状态、执行记录信息的等。

@restcontroller
@requestmapping("/api/task")
public class taskcontroller {
 
    @autowired
    private taskservice service;
 
    @requestmapping("/start")
    public object start(int id){
        try {
            service.startjob(id);
            return rtndata.ok();
        } catch (exception e) {
            return rtndata.fail(e.getmessage());
        }
    }
 
    @requestmapping("/pause")
    public object pause(int id){
        try {
            service.pausejob(id);
            return rtndata.ok();
        } catch (exception e) {
            return rtndata.fail(e.getmessage());
        }
    }
 
    @requestmapping("/resume")
    public object resume(int id){
        try {
            service.resumejob(id);
            return rtndata.ok();
        } catch (exception e) {
            return rtndata.fail(e.getmessage());
        }
    }
 
    @requestmapping("/remove")
    public object remove(int id){
        try {
            service.deletejob(id);
            return rtndata.ok();
        } catch (exception e) {
            return rtndata.fail(e.getmessage());
        }
    }
}

以上就是springboot创建动态定时任务的几种方式小结的详细内容,更多关于springboot动态定时任务的资料请关注其它相关文章!

免费资源网,https://freexyz.cn/
返回顶部
顶部
网站地图