基于spring task实现定时任务

定时任务。

定时任务在项目中的应用:

  • 每日凌晨对前一日的数据进行汇总
  • 定时清理系统缓存
  • 对每日的数据进行分析和总结
  • 银行月底汇总账单
  • 月底话费账单
  • 订单在30分钟内未支付会自动取消
  • 文章的缓存更新

一、基于注解的方式

启动类中加入注解,@EnableScheduling 注解。

入门案例

@Scheduled(cron = "*/1 * * * * ?")
public void time(){
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    String now = sdf.format(new Date());
    System.out.println("the time is "+now);
}

@Scheduled(cron = "*/6 * * * * ?") // 每6秒执行一次
public void sayHello() {
    System.out.println("Hello world!");
}

image.png
如果是单独起一个类来做定时任务的话,需要在类上加上@Component注解,而且需要将定时任务类置于启动类的位置之上。

@Scheduled注解参数详解

@Scheduled除过cron还有三种方式:fixedRate,fixedDelay,initialDelay
_cron:表达式可以定制化执行任务,但是执行的方式是与fixedDelay相近的,也是会按照上一次方法结束时间开始算起。
fixedRate:_控制方法执行的间隔时间,是以上一次方法执行完开始算起,如上一次方法执行阻塞住了,那么直到上一次执行完,并间隔给定的时间后,执行下一次。

//每3秒执行一次
    @Scheduled(fixedDelay = 3000)
    public void sayHello(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String now = sdf.format(new Date());
        System.out.println("This is a user task, the time is " + now);
    }

_fixedRate:_是按照一定的速率执行,是从上一次方法执行开始的时间算起,如果上一次方法阻塞住了,下一次也是不会执行,但是在阻塞这段时间内累计应该执行的次数,当不再阻塞时,一下子把这些全部执行掉,而后再按照固定速率继续执行。

@Scheduled(fixedRate = 10000)
    public void sayHello(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String now = sdf.format(new Date());
        System.out.println("This is a user task, the time is " + now);
    }

_initialDelay:_initialDelay = 10000 表示在容器启动后,延迟10秒后再执行一次定时器。

@Scheduled(initialDelay = 10000)
    public void sayHello(){
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String now = sdf.format(new Date());
        System.out.println("This is a user task, the time is " + now);
    }

cron解释

cron表达式是一个字符串,分为6或7个域,每两个域之间用空格分隔,
其语法格式为:“秒域 分域 时域 日域 月域 周域 年域”

取值范围

image.png

常例

表达式意义
*/5 * * * * ?每隔5秒钟执行一次
0 0 8 ? * L每周六8点执行一次
0 55 23 * * ?每天23点55分执行一次
0 0 23 L * ?每月最后一天23点执行一次
0 15 10 ? * 2-6表示周一到周五每天上午10:15执行

二、基于接口的方式

使用@Scheduled 注解很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,那么可以使用接口来完成定时任务,统一将定时器信息存放在数据库中。
在mysql中执行一下脚本插入定时任务:

drop table if exists `scheduled`;
create table `scheduled` (
 `cron_id` varchar(30) NOT NULL primary key,
 `cron_name` varchar(30) NULL,
 `cron` varchar(30) NOT NULL
);
insert into `scheduled` values ('1','定时器任务一','0/6 * * * * ?');

获取cron表达式

package com.cqie.datauser.dao;

import org.apache.ibatis.annotations.Select;
import org.springframework.stereotype.Repository;

/**
 * @Author QingYuQiao
 * @date 2024/5/10  9:24
 */
@Repository
public interface CronDao {


    @Select("select cron from scheduled where cron_id = #{id}")
    String getCron(int id);
}

定时任务配置及其执行

package com.cqie.datauser.task;

import com.cqie.datauser.dao.CronDao;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * @Author QingYuQiao
 * @date 2024/5/10  9:25
 */

@Component
public class MyTask implements SchedulingConfigurer {

    @Resource
    private CronDao cronDao;


    /**
     * 配置定时任务
     * @param taskRegistrar the registrar to be configured.
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(() -> process(),
                triggerContext -> {
                    String cron = cronDao.getCron(1);
                    if (cron.isEmpty()) {
                        System.out.println("cron为空");
                    }
                    return new CronTrigger(cron).nextExecutionTime(triggerContext);
                });
    }

    /**
     * 定时任务方法
     */
    public void process() {
        System.out.println("基于接口的定时任务执行");
    }
}

image.png

三、基于注解设定多线程定时任务

常规定时任务会受到上一次任务执行的时间影响。那么可以开启多线程执行周期任务。
@EnableScheduling// 1.开启定时任务
@EnableAsync// 2.开启多线程
启动类上加上这两个注解。

package com.cqie.datauser.task;

import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

/**
 * @Author QingYuQiao
 * @date 2024/5/10  9:42
 * 多线程定时任务
 */
@Component
public class MultiThreadTask {


    @Async
    @Scheduled(fixedDelay = 1000)  //间隔1秒
    public void first() throws InterruptedException {
        System.out.println("第一个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
        Thread.sleep(1000 * 10);
    }

    @Async
    @Scheduled(fixedDelay = 2000)
    public void second() {
        System.out.println("第二个定时任务开始 : " + LocalDateTime.now().toLocalTime() + "\r\n线程 : " + Thread.currentThread().getName());
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Object-v

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值