定时任务—写的不好,不要看

本文介绍了计划任务的概念,如系统级和用户级定时任务,并详细讲解了为何需要计划任务,例如数据备份、订单管理和数据抓取。特别地,文章探讨了SpringBoot如何利用SchedulingConfigurer接口实现动态定时任务,包括编写业务方法接口和实现configureTasks()方法的步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

计划任务

什么是计划任务(Crond)

计划任务—我们平时生活中的闹钟,定点执行

为什么要有计划任务

计划任务—主要是做一些周期性的任务,比如: 凌晨3点定时备份数据,订单超过三十分钟,取消订单。每十分钟抓取别的网站数据收为己用等等。

计划任务主要分两种

一、系统级别的定时任务:临时文件清理、系统信息采集、日志文件切割。二、用户级别的定时任务:定时备份系统配置文件、定时备份数据库的数据。

计划任务时间管理

root@Hyman[15:23:15]~# vim /etc/crontab
SHELL=/bin/bash                     #执行命令的解释器
PATH=/sbin:/bin:/usr/sbin:/usr/bin  #环境变量
MAILTO=root                         #邮件发给谁
# Example of job definition:
# .---------------- minute (0 - 59) #分钟
# |  .------------- hour (0 - 23)   #小时
# |  |  .---------- day of month (1 - 31)   #日期
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr #月份
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat  #星期
# |  |  |  |  |
# *  *  *  *  *   command to be executed

# *  表示任意的(分、时、日、月、周)时间都执行
# -  表示一个时间范围段,5-7点
# ,  表示分隔时段,6,0,4表示周六、日、四
# /1 表示每隔n单位时间,*/1010分钟


00 02 * * * ls           #每天的凌晨2点整执行
*/10  02 * * * ls        #每天凌晨2点,每隔10分钟执行一次
45 4 1-10 * * ls         #每月110日的4:45执行
45 4 1,10,22 * * ls      #每月11022日的4:45执行

SpringBoot基于SchedulingConfigurer接口实现动态定时任务

步骤:编写实体类-》定时执行的业务方法接口-》定时执行的业务方法接口实现-》实现SchedulingConfigurer接口,重写configureTasks()方法

@Entity
@Table(name = "SYS_TIMED_TASK")
public class TimedTaskEntity extends BaseEntity {
    private static final long serialVersionUID = 1L;
    public static String STATUS_START = "START";
    public static String STATUS_STOP = "STOP";
    @Column(name = "task_name", nullable = true)
    private String taskName;//定时任务名
    @Column(name = "status", nullable = true)//状态
    private String status = STATUS_STOP;
    @Column(name = "init_status")//初始状态
    private String initStatus = STATUS_START;
    @Column(name = "task_cron", nullable = true)
    private String cron;//定时任务时间管理
    @Column(name = "service_name", nullable = true, length = 255)
    private String serviceName;//调用的服务名
    @Column(name = "exe_method", nullable = true, length = 255)
    private String exeMethod;//调用的服务名中具体方法
    @Column(name = "task_desc", nullable = true, length = 255)
    private String description;//定时任务描述
    
    @Transient
    ScheduledTask scheduledTask;//计划任务
    @Transient
    Boolean scheduledTaskEnabled = false;
}

业务方法接口实现

    //假设刚添加的定时任务数据已经保存到数据库中-》接下来就是开始定时任务了
    @RequestMapping({"/start"})
	@ControllerLogExeTime(description="开启定时任务")
	public void start(String id ) {
		dynamicScheduledTaskServiceImpl.start(id);
	}

实现SchedulingConfigurer接口,重写configureTasks()方法

@Component(value = "dynamicScheduledTaskService")
public class DynamicScheduledTaskServiceImpl implements SchedulingConfigurer, ApplicationContextAware, DynamicScheduledTaskService {
    private Map<String, TimedTaskEntity> taskMap = new ConcurrentHashMap<String, TimedTaskEntity>();
    //开始定时任务
    synchronized public void start(String id) {
        //查询taskMap 是否含有该定时任务
        TimedTaskEntity transientTimedTaskEntity = this.taskMap.get(id);
        TimedTaskEntity timedTaskEntity = null;
        //没有该定时任务
        if (transientTimedTaskEntity == null) {
            timedTaskEntity = timedTaskService.get(id);
            if (timedTaskEntity != null) {
               //开启定时任务
               scheduleTriggerTask(transientTimedTaskEntity);
               //修改实体类中的开始状态信息               
               transientTimedTaskEntity.setStatus(TimedTaskEntity.STATUS_START);
            }
        }
    }
    
    //开启定时任务
    private void scheduleTriggerTask(TimedTaskEntity timedTaskEntity) {
        //检查该定时任务信息是否符合你们的要求
        check(timedTaskEntity);
        //将该定时任务添加到taskMap中
        this.taskMap.put(timedTaskEntity.getId(), timedTaskEntity);
        //触发器
        TriggerTask triggerTask = new TriggerTask(new Runnable() {
            @Override
            public void run() {
                Object serviceObject = applicationContext
                        .getBean(timedTaskEntity.getServiceName());
                try {
                    Method method = serviceObject.getClass()
                            .getMethod(timedTaskEntity.getExeMethod());
                    try {
                        method.invoke(serviceObject);
                    } catch (Throwable e) {
                        logger.error("invode service method  error", e);
                    }
                } catch (Throwable e) {
                    logger.error("get service method  error", e);
                }
            }
        }, new Trigger() {
            @Override
            public Date nextExecutionTime(TriggerContext triggerContext) {
                TimedTaskEntity entity = taskMap.get(timedTaskEntity.getId());
                CronTrigger trigger = new CronTrigger(entity.getCron());
                Date nextExecDate = trigger.nextExecutionTime(triggerContext);
                return nextExecDate;
            }
        });
        //计划任务的表示形式
        ScheduledTask scheduledTask = null;
        try {
            //调度指定的触发器任务
            scheduledTask = taskRegistrar.scheduleTriggerTask(triggerTask);
        } catch (Throwable e) {
            logger.error("schedule trigger task error", e);
            if(scheduledTask != null){
                this.taskMap.remove(timedTaskEntity.getId());
                scheduledTask.cancel();
            }
        }
        if(scheduledTask != null){
            timedTaskEntity.setScheduledTask(scheduledTask);
            TimedTaskEntity entity = timedTaskRepository.get(timedTaskEntity.getId());
            entity.setStatus(TimedTaskEntity.STATUS_START);
            this.timedTaskRepository.save(entity);
        }
    }



    public void check(TimedTaskEntity timedTaskEntity) {
        String serviceName = timedTaskEntity.getServiceName();
        Object serviceObject = null;
        try {
            serviceObject = applicationContext.getBean(serviceName);
        } catch (Throwable e) {
            logger.error("can't find  service  " + serviceName);
            Assert.throwException("sys.timedTask.notFindService", serviceName);
        }
        serviceObject.getClass();
        String methodName = timedTaskEntity.getExeMethod();
        try {
            serviceObject.getClass().getMethod(methodName);
        } catch (Exception e) {
            logger.error("can't find  method " + methodName);
            Assert.throwException("sys.timedTask.notFindMethod", methodName);
        }
        String cron = timedTaskEntity.getCron();
        boolean flag = false;
        try {
            flag = CronSequenceGenerator.isValidExpression(cron);
        } catch (Exception e) {
            logger.error("cron is error " + cron);
            Assert.throwException("sys.timedTask.cronError", cron);
        }
        if (!flag) {
            Assert.throwException("sys.timedTask.cronError", cron);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值