创新实训(18)——springboot定时任务学习及实现用户浏览记录的定时抽取

定时任务的创建

在 Spring 中 可以通过 @EnableScheduling 和 @Scheduled 这两个注解来实现定时任务,接下来看下这两个注解:
(1)@EnableScheduling
可以通过在启动类上添加@EnableScheduling开启定时任务功能
(2)@Scheduled
在定时任务方法上使用@Schedule注解标记定时任务并配置定时任务执行时机。

  • 固定延迟时间:
// 初次调用延迟3秒,任务结束后5秒钟再次调用,两次调用不会同步运行
@Scheduled(initialDelay = 3000, fixedDelay = 5000)
public void timerTask() {
    try {
        System.out.println(System.currentTimeMillis() / 1000);
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}
  • 固定间隔时间:
// 初次调用延迟3秒,每隔5秒钟调用一次,多次调用可能同步运行
@Scheduled(initialDelay = 3000, fixedRate = 5000)
public void timerTask() {
    System.out.println(System.currentTimeMillis() / 1000);
}
  • 通过cron表达式配置:
// 从第0秒开始每10秒钟执行一次
@Scheduled(cron = "0/10 * * * * ?")
public void timerTask() {
    System.out.println(System.currentTimeMillis() / 1000);
}
// 从配置文件中读取cron表达式
@Scheduled(cron = "${task.cron}")
public void timerTask() {
    System.out.println(System.currentTimeMillis() / 1000);
}

Cron表达式详解

在这里插入图片描述

动态修改定时任务配置

可以通过实现SchedulingConfigurer接口来配置定时任务,实现不用重启服务修改定时器的cron:

@Component
public class DynamicTask implements SchedulingConfigurer {

    private CronTrigger trigger = new CronTrigger("5/10 * * * * ?");

    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        taskRegistrar.addTriggerTask(new Runnable() {
            @Override
            public void run() {
                System.out.println("来自定时器:" + System.currentTimeMillis() / 1000);
            }
        }, new Trigger() {
            @Nullable
            @Override
            public Date nextExecutionTime(TriggerContext context) {
                if (trigger != null) {
                    return trigger.nextExecutionTime(context);
                }
                return null;
            }
        });
    }

    public void setCron(String cron) {
        try {
            this.trigger = new CronTrigger(cron);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

但是上述方法在修改完cron表达式之后,只有再一次到达定时任务的时间,才会调用新的触发时间,导致页面设置的时间不能即时生效,以下改进方法可修正此问题:

@Service
public class ScheduleManager implements SchedulingConfigurer {
    private final Log logger = LogFactory.getLog(getClass());
    /**
     * 受ScheduleManager管理的任务集合
     */
    private final Map<Object, ScheduledTask> taskMap = new HashMap<>();
    /**
     * 定时任务注册器
     */
    private ScheduledTaskRegistrar taskRegistrar;

    /**
     * 系统启动时获取任务注册对象
     *
     * @param taskRegistrar 任务注册对象
     */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        this.taskRegistrar = taskRegistrar;
        logger.info("scheduleManager has successfully acquired the taskRegistrar");
    }

    /**
     * 添加新任务,如果存在key一致的任务,则取消原任务的执行,但添加新任务失败时原任务不会停止
     *
     * @param key      任务key
     * @param runnable 新任务执行代码
     * @param cron     新任务cron表达式
     */
    public void addTask(Object key, Runnable runnable, String cron) {
        if (runnable != null && !StringUtils.isEmpty(cron)) {
            ScheduledTask oldTask = taskMap.get(key);
            taskMap.put(key, taskRegistrar.scheduleCronTask(new CronTask(runnable, cron)));
            if (oldTask != null) {
                oldTask.cancel();
            }
        }
    }

    /**
     * 重置任务的执行时机,修改失败时任务仍使用原有执行时机
     *
     * @param key  任务key
     * @param cron 任务新cron表达式
     */
    public void modifyTask(Object key, String cron) {
        ScheduledTask oldTask = taskMap.get(key);
        if (oldTask != null && !StringUtils.isEmpty(cron)) {
            taskMap.put(key, taskRegistrar.scheduleCronTask(new CronTask(oldTask.getTask().getRunnable(), cron)));
            oldTask.cancel();
        }
    }

    /**
     * 取消任务执行
     *
     * @param key 任务key
     */
    public void cancelTask(Object key) {
        ScheduledTask task = taskMap.remove(key);
        if (task != null) {
            task.cancel();
        }
    }

    /**
     * 查看是否存在任务
     *
     * @param key 任务key
     * @return 如果任务存在返回true,否则返回false
     */
    public boolean existTask(Object key) {
        return taskMap.get(key) != null;
    }
}

实现用户浏览记录的定时抽取

(1)配置@EnableScheduling
在这里插入图片描述
(2)实现定时抽取方法每20分钟抽取一次


@Component
public class ExtractTask {

    @Resource
    private ExtractData extractData;
    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm:ss");

    /**
     * 定时抽取浏览数据 每20分钟一次
     */
    @Scheduled(cron = "0/10 * * * * ?")
    public void extract() {

        System.out.println(System.currentTimeMillis() / 1000);
        extractData.extractUserTagDate();
        extractData.extractUserTagDate();
    }
}

猜你喜欢

转载自blog.csdn.net/baidu_41871794/article/details/106769793
今日推荐